Code

rrdtool, rrdcached plugins: Re-implement value_list_to_filename().
[collectd.git] / src / plugin.c
index 5387f9c4b8a0c6e8c6c6922dda3604400a8486d1..809c140f7e0d1ee8f9047e39d5a7c17eed4cac8a 100644 (file)
@@ -96,6 +96,7 @@ static pthread_t      *read_threads = NULL;
 static int             read_threads_num = 0;
 
 static pthread_key_t   plugin_ctx_key;
+static _Bool           plugin_ctx_key_initialized = 0;
 
 /*
  * Static functions
@@ -297,7 +298,7 @@ static int plugin_load_file (char *file, uint32_t flags)
                dlh = lt_dlopenadvise(file, advise);
                lt_dladvise_destroy(&advise);
        } else {
-               dlh = lt_dlopen (file);
+               dlh = lt_dlopen (file);
        }
 #else /* if LIBTOOL_VERSION == 1 */
        if (flags & PLUGIN_FLAGS_GLOBAL)
@@ -358,28 +359,28 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                int rf_type;
                int rc;
 
-               /* Get the read function that needs to be read next. */
+               /* Get the read function that needs to be read next.
+                * We don't need to hold "read_lock" for the heap, but we need
+                * to call c_heap_get_root() and pthread_cond_wait() in the
+                * same protected block. */
+               pthread_mutex_lock (&read_lock);
                rf = c_heap_get_root (read_heap);
                if (rf == NULL)
                {
-                       struct timespec abstime;
-
-                       now = cdtime ();
-
-                       CDTIME_T_TO_TIMESPEC (now + interval_g, &abstime);
-
-                       pthread_mutex_lock (&read_lock);
-                       pthread_cond_timedwait (&read_cond, &read_lock,
-                                       &abstime);
-                       pthread_mutex_unlock (&read_lock);
+                       pthread_cond_wait (&read_cond, &read_lock);
+                        pthread_mutex_unlock (&read_lock);
                        continue;
                }
+               pthread_mutex_unlock (&read_lock);
 
                if ((rf->rf_interval.tv_sec == 0) && (rf->rf_interval.tv_nsec == 0))
                {
+                       /* this should not happen, because the interval is set
+                        * for each plugin when loading it
+                        * XXX: issue a warning? */
                        now = cdtime ();
 
-                       CDTIME_T_TO_TIMESPEC (interval_g, &rf->rf_interval);
+                       CDTIME_T_TO_TIMESPEC (plugin_get_interval (), &rf->rf_interval);
 
                        rf->rf_effective_interval = rf->rf_interval;
 
@@ -725,6 +726,9 @@ static int plugin_insert_read (read_func_t *rf)
        int status;
        llentry_t *le;
 
+       cdtime_t now = cdtime ();
+       CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
+
        pthread_mutex_lock (&read_lock);
 
        if (read_list == NULL)
@@ -780,6 +784,8 @@ static int plugin_insert_read (read_func_t *rf)
        /* This does not fail. */
        llist_append (read_list, le);
 
+       /* Wake up all the read threads. */
+       pthread_cond_broadcast (&read_cond);
        pthread_mutex_unlock (&read_lock);
        return (0);
 } /* int plugin_insert_read */
@@ -803,12 +809,13 @@ int plugin_register_read (const char *name,
        int status;
 
        if (ctx.interval != 0) {
+               /* If ctx.interval is not zero (== use the plugin or global
+                * interval), we need to use the "complex" read callback,
+                * because only that allows to specify a different interval.
+                * Wrap the callback using read_cb_wrapper(). */
                struct timespec interval;
                user_data_t user_data;
 
-               DEBUG ("plugin_register_read: plugin_interval = %.3f",
-                               CDTIME_T_TO_DOUBLE(plugin_interval));
-
                user_data.data = callback;
                user_data.free_func = NULL;
 
@@ -817,6 +824,9 @@ int plugin_register_read (const char *name,
                                name, read_cb_wrapper, &interval, &user_data);
        }
 
+       DEBUG ("plugin_register_read: default_interval = %.3f",
+                       CDTIME_T_TO_DOUBLE(plugin_get_interval ()));
+
        rf = malloc (sizeof (*rf));
        if (rf == NULL)
        {
@@ -877,6 +887,10 @@ int plugin_register_complex_read (const char *group, const char *name,
        }
        rf->rf_effective_interval = rf->rf_interval;
 
+       DEBUG ("plugin_register_read: interval = %i.%09i",
+                       (int) rf->rf_interval.tv_sec,
+                       (int) rf->rf_interval.tv_nsec);
+
        /* Set user data */
        if (user_data == NULL)
        {
@@ -1296,7 +1310,9 @@ int plugin_write (const char *plugin, /* {{{ */
     {
       callback_func_t *cf = le->value;
       plugin_write_cb callback;
-      plugin_ctx_t old_ctx = plugin_set_ctx (cf->cf_ctx);
+
+      /* do not switch plugin context; rather keep the context (interval)
+       * information of the calling read plugin */
 
       DEBUG ("plugin: plugin_write: Writing values via %s.", le->key);
       callback = cf->cf_callback;
@@ -1306,8 +1322,6 @@ int plugin_write (const char *plugin, /* {{{ */
       else
         success++;
 
-      plugin_set_ctx (old_ctx);
-
       le = le->next;
     }
 
@@ -1320,7 +1334,6 @@ int plugin_write (const char *plugin, /* {{{ */
   {
     callback_func_t *cf;
     plugin_write_cb callback;
-    plugin_ctx_t old_ctx;
 
     le = llist_head (list_write);
     while (le != NULL)
@@ -1336,13 +1349,12 @@ int plugin_write (const char *plugin, /* {{{ */
 
     cf = le->value;
 
-    old_ctx = plugin_set_ctx (cf->cf_ctx);
+    /* do not switch plugin context; rather keep the context (interval)
+     * information of the calling read plugin */
 
     DEBUG ("plugin: plugin_write: Writing values via %s.", le->key);
     callback = cf->cf_callback;
     status = (*callback) (ds, vl, &cf->cf_udata);
-
-    plugin_set_ctx (old_ctx);
   }
 
   return (status);
@@ -1535,13 +1547,25 @@ int plugin_dispatch_values (value_list_t *vl)
        if (vl->time == 0)
                vl->time = cdtime ();
 
-       if (vl->interval <= 0) {
+       if (vl->interval <= 0)
+       {
                plugin_ctx_t ctx = plugin_get_ctx ();
 
                if (ctx.interval != 0)
                        vl->interval = ctx.interval;
                else
-                       vl->interval = interval_g;
+               {
+                       char name[6 * DATA_MAX_NAME_LEN];
+                       FORMAT_VL (name, sizeof (name), vl);
+                       ERROR ("plugin_dispatch_values: Unable to determine "
+                                       "interval from context for "
+                                       "value list \"%s\". "
+                                       "This indicates a broken plugin. "
+                                       "Please report this problem to the "
+                                       "collectd mailing list or at "
+                                       "<http://collectd.org/bugs/>.", name);
+                       vl->interval = cf_get_default_interval ();
+               }
        }
 
        DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
@@ -1730,14 +1754,14 @@ int plugin_dispatch_notification (const notification_t *notif)
        {
                callback_func_t *cf;
                plugin_notification_cb callback;
-               plugin_ctx_t old_ctx;
                int status;
 
+               /* do not switch plugin context; rather keep the context
+                * (interval) information of the calling plugin */
+
                cf = le->value;
-               old_ctx = plugin_set_ctx (cf->cf_ctx);
                callback = cf->cf_callback;
                status = (*callback) (notif, &cf->cf_udata);
-               plugin_set_ctx (old_ctx);
                if (status != 0)
                {
                        WARNING ("plugin_dispatch_notification: Notification "
@@ -1778,19 +1802,57 @@ void plugin_log (int level, const char *format, ...)
        {
                callback_func_t *cf;
                plugin_log_cb callback;
-               plugin_ctx_t old_ctx;
 
                cf = le->value;
-               old_ctx = plugin_set_ctx (cf->cf_ctx);
                callback = cf->cf_callback;
 
+               /* do not switch plugin context; rather keep the context
+                * (interval) information of the calling plugin */
+
                (*callback) (level, msg, &cf->cf_udata);
 
-               plugin_set_ctx (old_ctx);
                le = le->next;
        }
 } /* void plugin_log */
 
+int parse_log_severity (const char *severity)
+{
+       int log_level = -1;
+
+       if ((0 == strcasecmp (severity, "emerg"))
+                       || (0 == strcasecmp (severity, "alert"))
+                       || (0 == strcasecmp (severity, "crit"))
+                       || (0 == strcasecmp (severity, "err")))
+               log_level = LOG_ERR;
+       else if (0 == strcasecmp (severity, "warning"))
+               log_level = LOG_WARNING;
+       else if (0 == strcasecmp (severity, "notice"))
+               log_level = LOG_NOTICE;
+       else if (0 == strcasecmp (severity, "info"))
+               log_level = LOG_INFO;
+#if COLLECT_DEBUG
+       else if (0 == strcasecmp (severity, "debug"))
+               log_level = LOG_DEBUG;
+#endif /* COLLECT_DEBUG */
+
+       return (log_level);
+} /* int parse_log_severity */
+
+int parse_notif_severity (const char *severity)
+{
+       int notif_severity = -1;
+
+       if (strcasecmp (severity, "FAILURE") == 0)
+               notif_severity = NOTIF_FAILURE;
+       else if (strcmp (severity, "OKAY") == 0)
+               notif_severity = NOTIF_OKAY;
+       else if ((strcmp (severity, "WARNING") == 0)
+                       || (strcmp (severity, "WARN") == 0))
+               notif_severity = NOTIF_WARNING;
+
+       return (notif_severity);
+} /* int parse_notif_severity */
+
 const data_set_t *plugin_get_ds (const char *name)
 {
        data_set_t *ds;
@@ -1999,6 +2061,7 @@ static plugin_ctx_t *plugin_ctx_create (void)
        }
 
        *ctx = ctx_init;
+       assert (plugin_ctx_key_initialized);
        pthread_setspecific (plugin_ctx_key, ctx);
        DEBUG("Created new plugin context.");
        return (ctx);
@@ -2007,12 +2070,14 @@ static plugin_ctx_t *plugin_ctx_create (void)
 void plugin_init_ctx (void)
 {
        pthread_key_create (&plugin_ctx_key, plugin_ctx_destructor);
+       plugin_ctx_key_initialized = 1;
 } /* void plugin_init_ctx */
 
 plugin_ctx_t plugin_get_ctx (void)
 {
        plugin_ctx_t *ctx;
 
+       assert (plugin_ctx_key_initialized);
        ctx = pthread_getspecific (plugin_ctx_key);
 
        if (ctx == NULL) {
@@ -2030,6 +2095,7 @@ plugin_ctx_t plugin_set_ctx (plugin_ctx_t ctx)
        plugin_ctx_t *c;
        plugin_ctx_t old;
 
+       assert (plugin_ctx_key_initialized);
        c = pthread_getspecific (plugin_ctx_key);
 
        if (c == NULL) {
@@ -2045,6 +2111,17 @@ plugin_ctx_t plugin_set_ctx (plugin_ctx_t ctx)
        return (old);
 } /* void plugin_set_ctx */
 
+cdtime_t plugin_get_interval (void)
+{
+       cdtime_t interval;
+
+       interval = plugin_get_ctx().interval;
+       if (interval > 0)
+               return interval;
+
+       return cf_get_default_interval ();
+} /* cdtime_t plugin_get_interval */
+
 typedef struct {
        plugin_ctx_t ctx;
        void *(*start_routine) (void *);