Merge branch 'collectd-4.4'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 6 May 2008 11:45:25 +0000 (13:45 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 6 May 2008 11:45:25 +0000 (13:45 +0200)
TODO
configure.in
src/Makefile.am
src/collectd.conf.pod
src/collectd.h
src/cpu.c
src/disk.c
src/powerdns.c
src/users.c

diff --git a/TODO b/TODO
index 2a5b7ca..08fcec1 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,3 +1,6 @@
+For version 4.4:
+* PowerDNS plugin
+
 For version 4.3:
 * unixsock plugin: Remove the custom cache if possible.
 
index e834ffd..d817bec 100644 (file)
@@ -2331,10 +2331,13 @@ fi
 # libstatgrab
 if test "x$with_libstatgrab" = "xyes"
 then
+       plugin_cpu="yes"
+       plugin_disk="yes"
        plugin_interface="yes"
        plugin_load="yes"
        plugin_memory="yes"
        plugin_swap="yes"
+       plugin_users="yes"
 fi
 
 if test "x$with_libcurl" = "xyes" && test "x$with_libxml2" = "xyes"
index fe4af77..1f7caef 100644 (file)
@@ -145,13 +145,19 @@ endif
 if BUILD_PLUGIN_CPU
 pkglib_LTLIBRARIES += cpu.la
 cpu_la_SOURCES = cpu.c
+cpu_la_CFLAGS =
 cpu_la_LDFLAGS = -module -avoid-version
+cpu_la_LIBADD = 
 if BUILD_WITH_LIBKSTAT
 cpu_la_LDFLAGS += -lkstat
 endif
 if BUILD_WITH_LIBDEVINFO
 cpu_la_LDFLAGS += -ldevinfo
 endif
+if BUILD_WITH_LIBSTATGRAB
+cpu_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+cpu_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
 collectd_LDADD += "-dlopen" cpu.la
 collectd_DEPENDENCIES += cpu.la
 endif
@@ -183,7 +189,9 @@ endif
 if BUILD_PLUGIN_DISK
 pkglib_LTLIBRARIES += disk.la
 disk_la_SOURCES = disk.c
+disk_la_CFLAGS =
 disk_la_LDFLAGS = -module -avoid-version
+disk_la_LIBADD = 
 if BUILD_WITH_LIBKSTAT
 disk_la_LDFLAGS += -lkstat
 endif
@@ -193,6 +201,10 @@ endif
 if BUILD_WITH_LIBIOKIT
 disk_la_LDFLAGS += -lIOKit
 endif
+if BUILD_WITH_LIBSTATGRAB
+disk_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)  
+disk_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
 collectd_LDADD += "-dlopen" disk.la
 collectd_DEPENDENCIES += disk.la
 endif
@@ -633,7 +645,13 @@ endif
 if BUILD_PLUGIN_USERS
 pkglib_LTLIBRARIES += users.la
 users_la_SOURCES = users.c
+users_la_CFLAGS =
 users_la_LDFLAGS = -module -avoid-version
+users_la_LIBADD =
+if BUILD_WITH_LIBSTATGRAB
+users_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+users_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
 collectd_LDADD += "-dlopen" users.la
 collectd_DEPENDENCIES += users.la
 endif
index 781e273..afa0571 100644 (file)
@@ -909,6 +909,139 @@ Sets the Time-To-Live of generated ICMP packets.
 
 =back
 
+=head2 Plugin C<powerdns>
+
+The C<powerdns> plugin queries statistics from an authoritative PowerDNS
+nameserver and/or a PowerDNS recursor. Since both offer a wide variety of
+values, many of which are probably meaningless to most users, but may be useful
+for some. So you may chose which values to collect, but if you don't, some
+reasonable defaults will be collected.
+
+  <Plugin "powerdns">
+    <Server "server_name">
+      Collect "latency"
+      Collect "udp-answers" "udp-queries"
+      Socket "/var/run/pdns.controlsocket"
+    </Server>
+    <Recursor "recursor_name">
+      Collect "questions"
+      Collect "cache-hits" "cache-misses"
+      Socket "/var/run/pdns_recursor.controlsocket"
+    </Recursor>
+    LocalSocket "/opt/collectd/var/run/collectd-powerdns"
+  </Plugin>
+
+=over 4
+
+=item B<Server> and B<Recursor> block
+
+The B<Server> block defines one authoritative server to query, the B<Recursor>
+does the same for an recursing server. The possible options in both blocks are
+the same, though. The argument defines a name for the serverE<nbsp>/ recursor
+and is required.
+
+=over 4
+
+=item B<Collect> I<Field>
+
+Using the B<Collect> statement you can select which values to collect. Here,
+you specify the name of the values as used by the PowerDNS servers, e.E<nbsp>g.
+C<dlg-only-drops>, C<answers10-100>.
+
+The method of getting the values differs for B<Server> and B<Recursor> blocks:
+When querying the server a C<SHOW *> command is issued in any case, because
+that's the only way of getting multiple values out of the server at once.
+collectd then picks out the values you have selected. When querying the
+recursor, a command is generated to query exactly these values. So if you
+specify invalid fields when querying the recursor, a syntax error may be
+returned by the daemon and collectd may not collect any values at all.
+
+If no B<Collect> statement is given, the following B<Server> values will be
+collected:
+
+=over 4
+
+=item latency
+
+=item packetcache-hit
+
+=item packetcache-miss
+
+=item packetcache-size
+
+=item query-cache-hit
+
+=item query-cache-miss
+
+=item recursing-answers
+
+=item recursing-questions
+
+=item tcp-answers
+
+=item tcp-queries
+
+=item udp-answers
+
+=item udp-queries
+
+=back
+
+The following B<Recursor> values will be collected by default:
+
+=over 4
+
+=item noerror-answers
+
+=item nxdomain-answers
+
+=item servfail-answers
+
+=item sys-msec
+
+=item user-msec
+
+=item qa-latency
+
+=item cache-entries
+
+=item cache-hits
+
+=item cache-misses
+
+=item questions
+
+=back
+
+Please note that up to that point collectd doesn't know what values are
+available on the server and values that are added do not need a change of the
+mechanism so far. However, the values must be mapped to collectd's naming
+scheme, which is done using a lookup table that lists all known values. If
+values are added in the future and collectd does not know about them, you will
+get an error much like this:
+
+  powerdns plugin: submit: Not found in lookup table: foobar = 42
+
+In this case please file a bug report with the collectd team.
+
+=item B<Socket> I<Path>
+
+Configures the path to the UNIX domain socket to be used when connecting to the
+daemon. By default C</var/run/pdns.controlsocket> will be used for an
+authoritative server and C</var/run/pdns_recursor.controlsocket> will be used
+for the recursor.
+
+=back
+
+=item B<LocalSocket> I<Path>
+
+Querying the recursor is done using UDP. When using UDP over UNIX domain
+sockets, the client socket needs a name in the file system, too. You can set
+this local name to I<Path> using the B<LocalSocket> option. The default is
+C<I<prefix>/var/run/collectd-powerdns>.
+
+=back
+
 =head2 Plugin C<processes>
 
 =over 4
index 80d86ba..55aac16 100644 (file)
 #endif
 
 #ifndef BYTE_ORDER
-# ifdef __BYTE_ORDER
+# if defined(_BYTE_ORDER)
+#  define BYTE_ORDER _BYTE_ORDER
+# elif defined(__BYTE_ORDER)
 #  define BYTE_ORDER __BYTE_ORDER
 # endif
 #endif
 #ifndef BIG_ENDIAN
-# ifdef __BIG_ENDIAN
+# if defined(_BIG_ENDIAN)
+#  define BIG_ENDIAN _BIG_ENDIAN
+# elif defined(__BIG_ENDIAN)
 #  define BIG_ENDIAN __BIG_ENDIAN
 # endif
 #endif
index 4d24125..7773dc4 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
 # endif
 #endif /* HAVE_SYSCTLBYNAME */
 
-#if !PROCESSOR_CPU_LOAD_INFO && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_SYSCTLBYNAME
+#if HAVE_STATGRAB_H
+# include <statgrab.h>
+#endif
+
+#if !PROCESSOR_CPU_LOAD_INFO && !KERNEL_LINUX && !HAVE_LIBKSTAT \
+       && !HAVE_SYSCTLBYNAME && !HAVE_LIBSTATGRAB
 # error "No applicable input method."
 #endif
 
@@ -98,7 +103,11 @@ static int numcpu;
 
 #elif defined(HAVE_SYSCTLBYNAME)
 static int numcpu;
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif defined(HAVE_LIBSTATGRAB)
+/* no variables needed */
+#endif /* HAVE_LIBSTATGRAB */
 
 static int init (void)
 {
@@ -152,7 +161,11 @@ static int init (void)
 
        if (numcpu != 1)
                NOTICE ("cpu: Only one processor supported when using `sysctlbyname' (found %i)", numcpu);
-#endif
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif defined(HAVE_LIBSTATGRAB)
+       /* nothing to initialize */
+#endif /* HAVE_LIBSTATGRAB */
 
        return (0);
 } /* int init */
@@ -370,7 +383,25 @@ static int cpu_read (void)
        submit (0, "nice", cpuinfo[CP_NICE]);
        submit (0, "system", cpuinfo[CP_SYS]);
        submit (0, "idle", cpuinfo[CP_IDLE]);
-#endif
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif defined(HAVE_LIBSTATGRAB)
+       sg_cpu_stats *cs;
+       cs = sg_get_cpu_stats ();
+
+       if (cs == NULL)
+       {
+              ERROR ("cpu plugin: sg_get_cpu_stats failed.");
+               return (-1);
+       }
+
+       submit (0, "idle",   (counter_t) cs->idle);
+       submit (0, "nice",   (counter_t) cs->nice);
+       submit (0, "swap",   (counter_t) cs->swap);
+       submit (0, "system", (counter_t) cs->kernel);
+       submit (0, "user",   (counter_t) cs->user);
+       submit (0, "wait",   (counter_t) cs->iowait);
+#endif /* HAVE_LIBSTATGRAB */
 
        return (0);
 }
index 23bec09..c5a0cc8 100644 (file)
 #  define UINT_MAX 4294967295U
 #endif
 
+#if HAVE_STATGRAB_H
+# include <statgrab.h>
+#endif
+
 #if HAVE_IOKIT_IOKITLIB_H
 static mach_port_t io_master_port = MACH_PORT_NULL;
 /* #endif HAVE_IOKIT_IOKITLIB_H */
@@ -98,6 +102,9 @@ static kstat_t *ksp[MAX_NUMDISK];
 static int numdisk = 0;
 /* #endif HAVE_LIBKSTAT */
 
+#elif defined(HAVE_LIBSTATGRAB)
+/* #endif HAVE_LIBKSTATGRAB */
+
 #else
 # error "No applicable input method."
 #endif
@@ -661,7 +668,23 @@ static int disk_read (void)
                                        kio.KIO_ROPS, kio.KIO_WOPS);
                }
        }
-#endif /* defined(HAVE_LIBKSTAT) */
+/* #endif defined(HAVE_LIBKSTAT) */
+
+#elif defined(HAVE_LIBSTATGRAB)
+       sg_disk_io_stats *ds;
+       int disks, counter;
+       char name[DATA_MAX_NAME_LEN];
+       
+       if ((ds = sg_get_disk_io_stats(&disks)) == NULL)
+               return (0);
+               
+       for (counter=0; counter < disks; counter++) {
+               strncpy(name, ds->disk_name, sizeof(name));
+               name[sizeof(name)-1] = '\0'; /* strncpy doesn't terminate longer strings */
+               disk_submit (name, "disk_octets", ds->read_bytes, ds->write_bytes);
+               ds++;
+       }
+#endif /* defined(HAVE_LIBSTATGRAB) */
 
        return (0);
 } /* int disk_read */
index 6a28856..672b505 100644 (file)
 #define SERVER_COMMAND "SHOW *"
 
 #define RECURSOR_SOCKET  "/var/run/pdns_recursor.controlsocket"
-#define RECURSOR_COMMAND "get all-outqueries answers0-1 " /* {{{ */ \
-  "answers100-1000 answers10-100 answers1-10 answers-slow cache-entries " \
-  "cache-hits cache-misses chain-resends client-parse-errors " \
-  "concurrent-queries dlg-only-drops ipv6-outqueries negcache-entries " \
-  "noerror-answers nsset-invalidations nsspeeds-entries nxdomain-answers " \
-  "outgoing-timeouts qa-latency questions resource-limits " \
-  "server-parse-errors servfail-answers spoof-prevents sys-msec " \
-  "tcp-client-overflow tcp-outqueries tcp-questions throttled-out " \
-  "throttled-outqueries throttle-entries unauthorized-tcp unauthorized-udp " \
-  "unexpected-packets unreachables user-msec" /* }}} */
+#define RECURSOR_COMMAND "get noerror-answers nxdomain-answers " \
+  "servfail-answers sys-msec user-msec qa-latency cache-entries cache-hits " \
+  "cache-misses questions"
 
 struct list_item_s;
 typedef struct list_item_s list_item_t;
 
 struct list_item_s
 {
+  enum
+  {
+    SRV_AUTHORITATIVE,
+    SRV_RECURSOR
+  } server_type;
   int (*func) (list_item_t *item);
   char *instance;
+
+  char **fields;
+  int fields_num;
   char *command;
+
   struct sockaddr_un sockaddr;
   int socktype;
 };
@@ -119,46 +121,64 @@ uptime              number of seconds process has been running (since 3.1.5)
 user-msec           number of CPU milliseconds spent in 'user' mode
 }}} */
 
+const char* const default_server_fields[] = /* {{{ */
+{
+  "latency"
+  "packetcache-hit",
+  "packetcache-miss",
+  "packetcache-size",
+  "query-cache-hit",
+  "query-cache-miss",
+  "recursing-answers",
+  "recursing-questions",
+  "tcp-answers",
+  "tcp-queries",
+  "udp-answers",
+  "udp-queries",
+}; /* }}} */
+int default_server_fields_num = STATIC_ARRAY_SIZE (default_server_fields);
+
 statname_lookup_t lookup_table[] = /* {{{ */
 {
-  /*
-   * Recursor statistics
-   */
-  /*
-   * corrupt-packets
-   * deferred-cache-inserts
-   * deferred-cache-lookup
-   * qsize-q
-   * servfail-packets
-   * timedout-packets
-   * udp4-answers
-   * udp4-queries
-   * udp6-answers
-   * udp6-queries
-   */
+  /*********************
+   * Server statistics *
+   *********************/
   /* Questions */
-  {"recursing-questions", "dns_question", "recurse"},
-  {"tcp-queries",         "dns_question", "tcp"},
-  {"udp-queries",         "dns_question", "udp"},
+  {"recursing-questions",    "dns_question", "recurse"},
+  {"tcp-queries",            "dns_question", "tcp"},
+  {"udp-queries",            "dns_question", "udp"},
 
   /* Answers */
-  {"recursing-answers",   "dns_answer",   "recurse"},
-  {"tcp-answers",         "dns_answer",   "tcp"},
-  {"udp-answers",         "dns_answer",   "udp"},
+  {"recursing-answers",      "dns_answer",   "recurse"},
+  {"tcp-answers",            "dns_answer",   "tcp"},
+  {"udp-answers",            "dns_answer",   "udp"},
 
   /* Cache stuff */
-  {"packetcache-hit",     "cache_result", "packet-hit"},
-  {"packetcache-miss",    "cache_result", "packet-miss"},
-  {"packetcache-size",    "cache_size",   "packet"},
-  {"query-cache-hit",     "cache_result", "query-hit"},
-  {"query-cache-miss",    "cache_result", "query-miss"},
+  {"packetcache-hit",        "cache_result", "packet-hit"},
+  {"packetcache-miss",       "cache_result", "packet-miss"},
+  {"packetcache-size",       "cache_size",   "packet"},
+  {"query-cache-hit",        "cache_result", "query-hit"},
+  {"query-cache-miss",       "cache_result", "query-miss"},
 
   /* Latency */
-  {"latency",             "latency",      NULL},
-
-  /*
-   * Recursor statistics
-   */
+  {"latency",                "latency",      NULL},
+
+  /* Other stuff.. */
+  {"corrupt-packets",        "io_packets",   "corrupt"},
+  {"deferred-cache-inserts", "counter",      "cache-deferred_insert"},
+  {"deferred-cache-lookup",  "counter",      "cache-deferred_lookup"},
+  {"qsize-a",                "cache_size",   "answers"},
+  {"qsize-q",                "cache_size",   "questions"},
+  {"servfail-packets",       "io_packets",   "servfail"},
+  {"timedout-packets",       "io_packets",   "timeout"},
+  {"udp4-answers",           "dns_answer",   "udp4"},
+  {"udp4-queries",           "dns_question", "queries-udp4"},
+  {"udp6-answers",           "dns_answer",   "udp6"},
+  {"udp6-queries",           "dns_question", "queries-udp6"},
+
+  /***********************
+   * Recursor statistics *
+   ***********************/
   /* Answers by return code */
   {"noerror-answers",     "dns_rcode",    "NOERROR"},
   {"nxdomain-answers",    "dns_rcode",    "NXDOMAIN"},
@@ -177,7 +197,35 @@ statname_lookup_t lookup_table[] = /* {{{ */
   {"cache-misses",        "cache_result", "miss"},
 
   /* Total number of questions.. */
-  {"questions",           "dns_qtype",    "total"}
+  {"questions",           "dns_qtype",    "total"},
+
+  /* All the other stuff.. */
+  {"all-outqueries",      "dns_question", "outgoing"},
+  {"answers0-1",          "dns_answer",   "0_1"},
+  {"answers1-10",         "dns_answer",   "1_10"},
+  {"answers10-100",       "dns_answer",   "10_100"},
+  {"answers100-1000",     "dns_answer",   "100_1000"},
+  {"answers-slow",        "dns_answer",   "slow"},
+  {"chain-resends",       "dns_question", "chained"},
+  {"client-parse-errors", "counter",      "drops-client_parse_error"},
+  {"concurrent-queries",  "dns_question", "concurrent"},
+  {"dlg-only-drops",      "counter",      "drops-delegation_only"},
+  {"negcache-entries",    "cache_size",   "negative"},
+  {"nsspeeds-entries",    "gauge",        "entries-ns_speeds"},
+  {"nsset-invalidations", "counter",      "ns_set_invalidation"},
+  {"outgoing-timeouts",   "counter",      "drops-timeout_outgoing"},
+  {"resource-limits",     "counter",      "drops-resource_limit"},
+  {"server-parse-errors", "counter",      "drops-server_parse_error"},
+  {"spoof-prevents",      "counter",      "drops-spoofed"},
+  {"tcp-client-overflow", "counter",      "denied-client_overflow_tcp"},
+  {"tcp-outqueries",      "dns_question", "outgoing-tcp"},
+  {"tcp-questions",       "dns_question", "incoming-tcp"},
+  {"throttled-out",       "dns_question", "outgoing-throttled"},
+  {"throttle-entries",    "gauge",        "entries-throttle"},
+  {"unauthorized-tcp",    "counter",      "denied-unauthorized_tcp"},
+  {"unauthorized-udp",    "counter",      "denied-unauthorized_udp"},
+  {"unexpected-packets",  "dns_answer",   "unexpected"}
+  /* {"uptime", "", ""} */
 }; /* }}} */
 int lookup_table_length = STATIC_ARRAY_SIZE (lookup_table);
 
@@ -186,6 +234,14 @@ static llist_t *list = NULL;
 #define PDNS_LOCAL_SOCKPATH LOCALSTATEDIR"/run/"PACKAGE_NAME"-powerdns"
 static char *local_sockpath = NULL;
 
+/* TODO: Do this before 4.4:
+ * - Recursor:
+ *   - Complete list of known pdns -> collectd mappings.
+ * - Update the collectd.conf(5) manpage.
+ *
+ * -octo
+ */
+
 /* <http://doc.powerdns.com/recursor-stats.html> */
 static void submit (const char *plugin_instance, /* {{{ */
     const char *pdns_type, const char *value)
@@ -208,7 +264,7 @@ static void submit (const char *plugin_instance, /* {{{ */
 
   if (i >= lookup_table_length)
   {
-    DEBUG ("powerdns plugin: submit: Not found in lookup table: %s = %s;",
+    INFO ("powerdns plugin: submit: Not found in lookup table: %s = %s;",
         pdns_type, value);
     return;
   }
@@ -478,15 +534,42 @@ static int powerdns_read_server (list_item_t *item) /* {{{ */
   char *key;
   char *value;
 
+  const char* const *fields;
+  int fields_num;
+
+  if (item->command == NULL)
+    item->command = strdup ("SHOW *");
+  if (item->command == NULL)
+  {
+    ERROR ("powerdns plugin: strdup failed.");
+    return (-1);
+  }
+
   status = powerdns_get_data (item, &buffer, &buffer_size);
   if (status != 0)
     return (-1);
 
+  if (item->fields_num != 0)
+  {
+    fields = (const char* const *) item->fields;
+    fields_num = item->fields_num;
+  }
+  else
+  {
+    fields = default_server_fields;
+    fields_num = default_server_fields_num;
+  }
+
+  assert (fields != NULL);
+  assert (fields_num > 0);
+
   /* corrupt-packets=0,deferred-cache-inserts=0,deferred-cache-lookup=0,latency=0,packetcache-hit=0,packetcache-miss=0,packetcache-size=0,qsize-q=0,query-cache-hit=0,query-cache-miss=0,recursing-answers=0,recursing-questions=0,servfail-packets=0,tcp-answers=0,tcp-queries=0,timedout-packets=0,udp-answers=0,udp-queries=0,udp4-answers=0,udp4-queries=0,udp6-answers=0,udp6-queries=0, */
   dummy = buffer;
   saveptr = NULL;
   while ((key = strtok_r (dummy, ",", &saveptr)) != NULL)
   {
+    int i;
+
     dummy = NULL;
 
     value = strchr (key, '=');
@@ -499,6 +582,13 @@ static int powerdns_read_server (list_item_t *item) /* {{{ */
     if (value[0] == '\0')
       continue;
 
+    /* Check if this item was requested. */
+    for (i = 0; i < fields_num; i++)
+      if (strcasecmp (key, fields[i]) == 0)
+       break;
+    if (i >= fields_num)
+      continue;
+
     submit (item->instance, key, value);
   } /* while (strtok_r) */
 
@@ -507,6 +597,49 @@ static int powerdns_read_server (list_item_t *item) /* {{{ */
   return (0);
 } /* }}} int powerdns_read_server */
 
+/*
+ * powerdns_update_recursor_command
+ *
+ * Creates a string that holds the command to be sent to the recursor. This
+ * string is stores in the `command' member of the `list_item_t' passed to the
+ * function. This function is called by `powerdns_read_recursor'.
+ */
+static int powerdns_update_recursor_command (list_item_t *li) /* {{{ */
+{
+  char buffer[4096];
+  int status;
+
+  if (li == NULL)
+    return (0);
+
+  if (li->fields_num < 1)
+  {
+    sstrncpy (buffer, RECURSOR_COMMAND, sizeof (buffer));
+  }
+  else
+  {
+    strcpy (buffer, "get ");
+    status = strjoin (&buffer[4], sizeof (buffer) - strlen ("get "),
+       li->fields, li->fields_num,
+       /* seperator = */ " ");
+    if (status < 0)
+    {
+      ERROR ("powerdns plugin: strjoin failed.");
+      return (-1);
+    }
+  }
+
+  buffer[sizeof (buffer) - 1] = 0;
+  li->command = strdup (buffer);
+  if (li->command == NULL)
+  {
+    ERROR ("powerdns plugin: strdup failed.");
+    return (-1);
+  }
+
+  return (0);
+} /* }}} int powerdns_update_recursor_command */
+
 static int powerdns_read_recursor (list_item_t *item) /* {{{ */
 {
   char *buffer = NULL;
@@ -521,6 +654,17 @@ static int powerdns_read_recursor (list_item_t *item) /* {{{ */
   char *value;
   char *value_saveptr;
 
+  if (item->command == NULL)
+  {
+    status = powerdns_update_recursor_command (item);
+    if (status != 0)
+    {
+      ERROR ("powerdns plugin: powerdns_update_recursor_command failed.");
+      return (-1);
+    }
+  }
+  assert (item->command != NULL);
+
   status = powerdns_get_data (item, &buffer, &buffer_size);
   if (status != 0)
     return (-1);
@@ -574,7 +718,54 @@ static int powerdns_config_add_string (const char *name, /* {{{ */
     return (-1);
 
   return (0);
-} /* }}} int ctail_config_add_string */
+} /* }}} int powerdns_config_add_string */
+
+static int powerdns_config_add_collect (list_item_t *li, /* {{{ */
+    oconfig_item_t *ci)
+{
+  int i;
+  char **temp;
+
+  if (ci->values_num < 1)
+  {
+    WARNING ("powerdns plugin: The `Collect' option needs "
+       "at least one argument.");
+    return (-1);
+  }
+
+  for (i = 0; i < ci->values_num; i++)
+    if (ci->values[i].type != OCONFIG_TYPE_STRING)
+    {
+      WARNING ("powerdns plugin: Only string arguments are allowed to "
+         "the `Collect' option.");
+      return (-1);
+    }
+
+  temp = (char **) realloc (li->fields,
+      sizeof (char *) * (li->fields_num + ci->values_num));
+  if (temp == NULL)
+  {
+    WARNING ("powerdns plugin: realloc failed.");
+    return (-1);
+  }
+  li->fields = temp;
+
+  for (i = 0; i < ci->values_num; i++)
+  {
+    li->fields[li->fields_num] = strdup (ci->values[i].value.string);
+    if (li->fields[li->fields_num] == NULL)
+    {
+      WARNING ("powerdns plugin: strdup failed.");
+      continue;
+    }
+    li->fields_num++;
+  }
+
+  /* Invalidate a previously computed command */
+  sfree (li->command);
+
+  return (0);
+} /* }}} int powerdns_config_add_collect */
 
 static int powerdns_config_add_server (oconfig_item_t *ci) /* {{{ */
 {
@@ -612,26 +803,32 @@ static int powerdns_config_add_server (oconfig_item_t *ci) /* {{{ */
    */
   if (strcasecmp ("Server", ci->key) == 0)
   {
+    item->server_type = SRV_AUTHORITATIVE;
     item->func = powerdns_read_server;
-    item->command = strdup (SERVER_COMMAND);
     item->socktype = SOCK_STREAM;
     socket_temp = strdup (SERVER_SOCKET);
   }
   else if (strcasecmp ("Recursor", ci->key) == 0)
   {
+    item->server_type = SRV_RECURSOR;
     item->func = powerdns_read_recursor;
-    item->command = strdup (RECURSOR_COMMAND);
     item->socktype = SOCK_DGRAM;
     socket_temp = strdup (RECURSOR_SOCKET);
   }
+  else
+  {
+    /* We must never get here.. */
+    assert (0);
+    return (-1);
+  }
 
   status = 0;
   for (i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *option = ci->children + i;
 
-    if (strcasecmp ("Command", option->key) == 0)
-      status = powerdns_config_add_string ("Command", &item->command, option);
+    if (strcasecmp ("Collect", option->key) == 0)
+      status = powerdns_config_add_collect (item, option);
     else if (strcasecmp ("Socket", option->key) == 0)
       status = powerdns_config_add_string ("Socket", &socket_temp, option);
     else
@@ -713,7 +910,7 @@ static int powerdns_config (oconfig_item_t *ci) /* {{{ */
     if ((strcasecmp ("Server", option->key) == 0)
        || (strcasecmp ("Recursor", option->key) == 0))
       powerdns_config_add_server (option);
-    if (strcasecmp ("LocalSocket", option->key) == 0)
+    else if (strcasecmp ("LocalSocket", option->key) == 0)
     {
       char *temp = strdup (option->key);
       if (temp == NULL)
index bec908c..5b12e98 100644 (file)
 #include "common.h"
 #include "plugin.h"
 
+#if HAVE_STATGRAB_H
+# include <statgrab.h>
+#endif /* HAVE_STATGRAB_H */
+
 #if HAVE_UTMPX_H
 # include <utmpx.h>
 /* #endif HAVE_UTMPX_H */
@@ -90,6 +94,16 @@ static int users_read (void)
        users_submit (users);
 /* #endif HAVE_GETUTENT */
 
+#elif HAVE_LIBSTATGRAB
+       sg_user_stats *us;
+
+       us = sg_get_user_stats ();
+       if (us == NULL)
+               return (-1);   
+
+       users_submit ((gauge_t) us->num_entries);
+/* #endif HAVE_LIBSTATGRAB */
+
 #else
 # error "No applicable input method."
 #endif