Code

uptime plugin: Add a plugin to measure the time a system has been running.
[collectd.git] / src / uptime.c
diff --git a/src/uptime.c b/src/uptime.c
new file mode 100644 (file)
index 0000000..f98be06
--- /dev/null
@@ -0,0 +1,227 @@
+/**
+ * collectd - src/uptime.c
+ * Copyright (C) 2009  Marco Chiappero
+ *
+ * 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:
+ *   Marco Chiappero <marco at absence.it>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#if KERNEL_LINUX
+# define UPTIME_FILE "/proc/uptime"
+/*
+   No need for includes, using /proc filesystem, Linux only.
+*/
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_LIBKSTAT
+/* something to include? maybe <sys/sysinfo.h> ? */
+/*
+   Using kstats chain to retrieve the boot time, this applies to:
+       - Solaris / OpenSolaris
+*/
+/* #endif HAVE_LIBKSTAT */
+
+#elif HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+/*
+   Using sysctl interface to retrieve the boot time, this applies to:
+       - *BSD
+        - Darwin / OS X
+*/
+/* #endif HAVE_SYS_SYSCTL_H */
+
+#else
+# error "No applicable input method."
+#endif
+
+
+#if !KERNEL_LINUX
+#define INIT_FAILED "uptime plugin: unable to calculate uptime, the plugin will be disabled."
+#endif
+
+
+#if KERNEL_LINUX
+/* global variables not needed*/
+
+#elif HAVE_SYS_SYSCTL_H || HAVE_LIBKSTAT
+static time_t boottime;
+# if HAVE_LIBKSTAT
+extern kstat_ctl_t *kc;
+# endif
+
+#endif
+
+
+static void uptime_submit (gauge_t uptime)
+{
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = uptime;
+
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "uptime", sizeof (vl.plugin));
+       sstrncpy (vl.type, "uptime", sizeof (vl.type));
+
+       plugin_dispatch_values (&vl);
+}
+
+#if !KERNEL_LINUX
+static int uptime_init (void)
+{
+/*     NOTE
+
+       On unix systems other than Linux there is no /proc filesystem which
+       calculates the uptime every time we call a read for the /proc/uptime
+       file, the only information available is the boot time (in unix time,
+       since epoch). Hence there is no need to read, every time the
+       plugin_read is called, a value that won't change: this is a right
+       task for the uptime_init function. However, since uptime_init is run
+       only once, if the function fails in retrieving the boot time, the
+       plugin is unregistered and there is no chance to try again later.
+       Nevertheless, this is very unlikely to happen.
+
+*/
+
+# if HAVE_LIBKSTAT
+
+       kstat_t *ksp;
+       kstat_named_t *knp;
+
+       ksp = NULL;
+       knp = NULL;
+
+       /* kstats chain already opened by update_kstat (using *kc), let's verify everything went fine. */
+       if ( kc == NULL )
+       {
+               ERROR ("uptime plugin: unable to open kstat control structure");
+               ERROR (INIT_FAILED);
+               return (-1);
+       }
+
+       if (( ksp = kstat_lookup (kc, "unix", 0, "system_misc")) == NULL )
+       {
+               ERROR ("uptime plugin: cannot find %s kstat", "unix:0:system_misc");
+               ERROR (INIT_FAILED);
+               return (-1);
+       }
+
+       if (( kstat_read (kc, ksp, NULL) < 0 ) ||
+               (( knp = (kstat_named_t *) kstat_data_lookup (ksp, "boot_time")) != NULL ))
+       {
+               ERROR ("uptime plugin: kstat data reading failed");
+               ERROR (INIT_FAILED);
+               return (-1);
+       }
+
+       boottime = (time_t) knp->value.ui32;
+
+/* #endif HAVE_LIBKSTAT */
+
+# elif HAVE_SYS_SYSCTL_H
+
+       struct timeval boottv;
+       size_t boottv_len;
+
+        int mib[2];
+
+        mib[0] = CTL_KERN;
+        mib[1] = KERN_BOOTTIME;
+
+        boottv_len = sizeof (boottv);
+
+        if (( sysctl (mib, 2, &boottv, &boottv_len, NULL, 0) != 0 ) || boottv.tv_sec == 0 )
+        {
+                char errbuf[1024];
+                ERROR ("uptime plugin: no value read from sysctl interface: %s",
+                        sstrerror (errno, errbuf, sizeof (errbuf)));
+               ERROR (INIT_FAILED);
+                return (-1);
+        }
+
+       boottime = boottv.tv_sec;
+
+/* #endif HAVE_SYS_SYSCTL_H */
+
+# endif
+
+       return (0);
+
+}
+#endif
+
+static int uptime_read (void)
+{
+       gauge_t uptime;
+
+#if KERNEL_LINUX
+
+       FILE *fh;
+
+       fh = fopen (UPTIME_FILE, "r");
+
+       if (fh == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("uptime plugin: cannot open %s: %s", UPTIME_FILE,
+                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       if ( fscanf (fh, "%lf", &uptime) < 1 )
+       {
+               WARNING ("no value read from %s", UPTIME_FILE);
+               fclose (fh);
+               return (-1);
+       }
+
+       fclose (fh);
+
+/* #endif KERNEL_LINUX */
+
+
+#elif HAVE_SYS_SYSCTL_H || HAVE_LIBKSTAT
+
+       time_t elapsed;
+
+       elapsed = time (NULL) - boottime;
+
+       uptime = (gauge_t) elapsed;
+
+/* #endif HAVE_SYS_SYSCTL_H */
+
+#endif
+
+       uptime_submit (uptime);
+
+       return (0);
+}
+
+void module_register (void)
+{
+#if !KERNEL_LINUX
+       plugin_register_init ("uptime", uptime_init);
+#endif
+       plugin_register_read ("uptime", uptime_read);
+} /* void module_register */