Merge branch 'collectd-4.10' into collectd-5.0
[collectd.git] / src / plugin.c
index 8358276..a749d1e 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/plugin.c
- * Copyright (C) 2005-2009  Florian octo Forster
+ * Copyright (C) 2005-2011  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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Sebastian Harl <sh at tokkee.org>
  **/
 
@@ -36,7 +36,6 @@
 #include "utils_llist.h"
 #include "utils_heap.h"
 #include "utils_cache.h"
-#include "utils_threshold.h"
 #include "filter_chain.h"
 
 /*
@@ -74,6 +73,7 @@ typedef struct read_func_s read_func_t;
 static llist_t *list_init;
 static llist_t *list_write;
 static llist_t *list_flush;
+static llist_t *list_missing;
 static llist_t *list_shutdown;
 static llist_t *list_log;
 static llist_t *list_notification;
@@ -280,8 +280,6 @@ static int plugin_load_file (char *file, uint32_t flags)
        lt_dlhandle dlh;
        void (*reg_handle) (void);
 
-       DEBUG ("file = %s", file);
-
        lt_dlinit ();
        lt_dlerror (); /* clear errors */
 
@@ -297,23 +295,35 @@ static int plugin_load_file (char *file, uint32_t flags)
        }
 #else /* if LIBTOOL_VERSION == 1 */
        if (flags & PLUGIN_FLAGS_GLOBAL)
-               ERROR ("plugin_load_file: The global flag is not supported, "
+               WARNING ("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 ();
+               char errbuf[1024] = "";
+
+               ssnprintf (errbuf, sizeof (errbuf),
+                               "lt_dlopen (\"%s\") failed: %s. "
+                               "The most common cause for this problem are "
+                               "missing dependencies. Use ldd(1) to check "
+                               "the dependencies of the plugin "
+                               "/ shared object.",
+                               file, lt_dlerror ());
+
+               ERROR ("%s", errbuf);
+               /* Make sure this is printed to STDERR in any case, but also
+                * make sure it's printed only once. */
+               if (list_log != NULL)
+                       fprintf (stderr, "ERROR: %s\n", errbuf);
 
-               ERROR ("lt_dlopen (%s) failed: %s", file, error);
-               fprintf (stderr, "lt_dlopen (%s) failed: %s\n", file, error);
                return (1);
        }
 
        if ((reg_handle = (void (*) (void)) lt_dlsym (dlh, "module_register")) == NULL)
        {
-               WARNING ("Couldn't find symbol `module_register' in `%s': %s\n",
+               WARNING ("Couldn't find symbol \"module_register\" in \"%s\": %s\n",
                                file, lt_dlerror ());
                lt_dlclose (dlh);
                return (-1);
@@ -336,7 +346,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
        while (read_loop != 0)
        {
                read_func_t *rf;
-               struct timeval now;
+               cdtime_t now;
                int status;
                int rf_type;
                int rc;
@@ -347,10 +357,9 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                {
                        struct timespec abstime;
 
-                       gettimeofday (&now, /* timezone = */ NULL);
+                       now = cdtime ();
 
-                       abstime.tv_sec = now.tv_sec + interval_g;
-                       abstime.tv_nsec = 1000 * now.tv_usec;
+                       CDTIME_T_TO_TIMESPEC (now + interval_g, &abstime);
 
                        pthread_mutex_lock (&read_lock);
                        pthread_cond_timedwait (&read_cond, &read_lock,
@@ -361,15 +370,13 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
 
                if ((rf->rf_interval.tv_sec == 0) && (rf->rf_interval.tv_nsec == 0))
                {
-                       gettimeofday (&now, /* timezone = */ NULL);
+                       now = cdtime ();
 
-                       rf->rf_interval.tv_sec = interval_g;
-                       rf->rf_interval.tv_nsec = 0;
+                       CDTIME_T_TO_TIMESPEC (interval_g, &rf->rf_interval);
 
                        rf->rf_effective_interval = rf->rf_interval;
 
-                       rf->rf_next_read.tv_sec = now.tv_sec;
-                       rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
+                       CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
                }
 
                /* sleep until this entry is due,
@@ -459,7 +466,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                }
 
                /* update the ``next read due'' field */
-               gettimeofday (&now, /* timezone = */ NULL);
+               now = cdtime ();
 
                DEBUG ("plugin_read_thread: Effective interval of the "
                                "%s plugin is %i.%09i.",
@@ -476,15 +483,12 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                NORMALIZE_TIMESPEC (rf->rf_next_read);
 
                /* Check, if `rf_next_read' is in the past. */
-               if ((rf->rf_next_read.tv_sec < now.tv_sec)
-                               || ((rf->rf_next_read.tv_sec == now.tv_sec)
-                                       && (rf->rf_next_read.tv_nsec < (1000 * now.tv_usec))))
+               if (TIMESPEC_TO_CDTIME_T (&rf->rf_next_read) < now)
                {
                        /* `rf_next_read' is in the past. Insert `now'
                         * so this value doesn't trail off into the
                         * past too much. */
-                       rf->rf_next_read.tv_sec = now.tv_sec;
-                       rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
+                       CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
                }
 
                DEBUG ("plugin_read_thread: Next read of the %s plugin at %i.%09i.",
@@ -734,6 +738,17 @@ static int plugin_insert_read (read_func_t *rf)
                }
        }
 
+       le = llist_search (read_list, rf->rf_name);
+       if (le != NULL)
+       {
+               pthread_mutex_unlock (&read_lock);
+               WARNING ("The read function \"%s\" is already registered. "
+                               "Check for duplicate \"LoadPlugin\" lines "
+                               "in your configuration!",
+                               rf->rf_name);
+               return (EINVAL);
+       }
+
        le = llentry_create (rf->rf_name, rf);
        if (le == NULL)
        {
@@ -762,14 +777,13 @@ int plugin_register_read (const char *name,
                int (*callback) (void))
 {
        read_func_t *rf;
+       int status;
 
-       rf = (read_func_t *) malloc (sizeof (read_func_t));
+       rf = malloc (sizeof (*rf));
        if (rf == NULL)
        {
-               char errbuf[1024];
-               ERROR ("plugin_register_read: malloc failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
-               return (-1);
+               ERROR ("plugin_register_read: malloc failed.");
+               return (ENOMEM);
        }
 
        memset (rf, 0, sizeof (read_func_t));
@@ -783,7 +797,11 @@ int plugin_register_read (const char *name,
        rf->rf_interval.tv_nsec = 0;
        rf->rf_effective_interval = rf->rf_interval;
 
-       return (plugin_insert_read (rf));
+       status = plugin_insert_read (rf);
+       if (status != 0)
+               sfree (rf);
+
+       return (status);
 } /* int plugin_register_read */
 
 int plugin_register_complex_read (const char *group, const char *name,
@@ -792,12 +810,13 @@ int plugin_register_complex_read (const char *group, const char *name,
                user_data_t *user_data)
 {
        read_func_t *rf;
+       int status;
 
-       rf = (read_func_t *) malloc (sizeof (read_func_t));
+       rf = malloc (sizeof (*rf));
        if (rf == NULL)
        {
                ERROR ("plugin_register_complex_read: malloc failed.");
-               return (-1);
+               return (ENOMEM);
        }
 
        memset (rf, 0, sizeof (read_func_t));
@@ -825,7 +844,11 @@ int plugin_register_complex_read (const char *group, const char *name,
                rf->rf_udata = *user_data;
        }
 
-       return (plugin_insert_read (rf));
+       status = plugin_insert_read (rf);
+       if (status != 0)
+               sfree (rf);
+
+       return (status);
 } /* int plugin_register_complex_read */
 
 int plugin_register_write (const char *name,
@@ -842,7 +865,14 @@ int plugin_register_flush (const char *name,
                                (void *) callback, ud));
 } /* int plugin_register_flush */
 
-int plugin_register_shutdown (char *name,
+int plugin_register_missing (const char *name,
+               plugin_missing_cb callback, user_data_t *ud)
+{
+       return (create_register_callback (&list_missing, name,
+                               (void *) callback, ud));
+} /* int plugin_register_missing */
+
+int plugin_register_shutdown (const char *name,
                int (*callback) (void))
 {
        return (create_register_callback (&list_shutdown, name,
@@ -1028,6 +1058,11 @@ int plugin_unregister_flush (const char *name)
        return (plugin_unregister (list_flush, name));
 }
 
+int plugin_unregister_missing (const char *name)
+{
+       return (plugin_unregister (list_missing, name));
+}
+
 int plugin_unregister_shutdown (const char *name)
 {
        return (plugin_unregister (list_shutdown, name));
@@ -1296,7 +1331,8 @@ void plugin_shutdown_all (void)
 
        destroy_read_heap ();
 
-       plugin_flush (/* plugin = */ NULL, /* timeout = */ -1,
+       plugin_flush (/* plugin = */ NULL,
+                       /* timeout = */ 0,
                        /* identifier = */ NULL);
 
        le = NULL;
@@ -1326,6 +1362,7 @@ void plugin_shutdown_all (void)
         * the real free function when registering the write callback. This way
         * the data isn't freed twice. */
        destroy_all_callbacks (&list_flush);
+       destroy_all_callbacks (&list_missing);
        destroy_all_callbacks (&list_write);
 
        destroy_all_callbacks (&list_notification);
@@ -1333,6 +1370,44 @@ void plugin_shutdown_all (void)
        destroy_all_callbacks (&list_log);
 } /* void plugin_shutdown_all */
 
+int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */
+{
+  llentry_t *le;
+
+  if (list_missing == NULL)
+    return (0);
+
+  le = llist_head (list_missing);
+  while (le != NULL)
+  {
+    callback_func_t *cf;
+    plugin_missing_cb callback;
+    int status;
+
+    cf = le->value;
+    callback = cf->cf_callback;
+
+    status = (*callback) (vl, &cf->cf_udata);
+    if (status != 0)
+    {
+      if (status < 0)
+      {
+        ERROR ("plugin_dispatch_missing: Callback function \"%s\" "
+            "failed with status %i.",
+            le->key, status);
+        return (status);
+      }
+      else
+      {
+        return (0);
+      }
+    }
+
+    le = le->next;
+  }
+  return (0);
+} /* int }}} plugin_dispatch_missing */
+
 int plugin_dispatch_values (value_list_t *vl)
 {
        int status;
@@ -1348,7 +1423,8 @@ int plugin_dispatch_values (value_list_t *vl)
        if ((vl == NULL) || (vl->type[0] == 0)
                        || (vl->values == NULL) || (vl->values_len < 1))
        {
-               ERROR ("plugin_dispatch_values: Invalid value list.");
+               ERROR ("plugin_dispatch_values: Invalid value list "
+                               "from plugin %s.", vl->plugin);
                return (-1);
        }
 
@@ -1389,11 +1465,12 @@ int plugin_dispatch_values (value_list_t *vl)
        if (vl->interval <= 0)
                vl->interval = interval_g;
 
-       DEBUG ("plugin_dispatch_values: time = %.3f; interval = %i; "
+       DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
                        "host = %s; "
                        "plugin = %s; plugin_instance = %s; "
                        "type = %s; type_instance = %s;",
-                       CDTIME_T_TO_DOUBLE (vl->time), vl->interval,
+                       CDTIME_T_TO_DOUBLE (vl->time),
+                       CDTIME_T_TO_DOUBLE (vl->interval),
                        vl->host,
                        vl->plugin, vl->plugin_instance,
                        vl->type, vl->type_instance);
@@ -1477,9 +1554,6 @@ int plugin_dispatch_values (value_list_t *vl)
        /* Update the value cache */
        uc_update (ds, vl);
 
-       /* Initiate threshold checking */
-       ut_check_threshold (ds, vl);
-
        if (post_cache_chain != NULL)
        {
                status = fc_process_chain (ds, vl, post_cache_chain);