From 0c3fcab4abed820084393e64dc30a88512941de1 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Thu, 19 Mar 2009 13:30:32 +0100 Subject: [PATCH] uptime plugin: Add a plugin to measure the time a system has been running. Florian Forster ha scritto: >Hi Marco, Hi Florian, > Checking the KSTAT_TYPE_NAMED twice (three times if you count the > assertion) is of course not necessary. I suspect a copy'n'paste error ;) Me too. Please remove the second one at least, kstat_read do not change ks_type. >A quick `grep' revealed that `get_kstat' is only used in two places, the >memory and the swap plugin - both trying to figure out the pagesize. If >you need something else than `KSTAT_TYPE_NAMED', I'd suggest to move the >checks to a new function `get_kstat_pagesize' and use that function in >the two plugins. I went for the kstat.h only solution. Ok, I'm attaching the code, please check the preprocessor directives for the includes section, I don't much about defines created by the build system and its names. I'm using it right now on a linux machine, but I haven't tested yet on Solaris and BSDs. Today I tried to compile it on OpenSolaris, but after fighting with the packaging system and many other things I gave up and decided I won't try anymore. So, since I'd like to say the plugin is done after testing it, Solaris testers are wanted :P As soon as I can I will edit the wiki page, but first I want to have a closer look to the iptable plugin and see how many modifications are needed for IPv6 and then have an opinion about the single vs. double plugin approach. See you soon :) Regars, Marco --- src/types.db | 1 + src/uptime.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 src/uptime.c diff --git a/src/types.db b/src/types.db index f0525fe4..05f5f791 100644 --- a/src/types.db +++ b/src/types.db @@ -110,6 +110,7 @@ temperature value:GAUGE:-273.15:U time_dispersion seconds:GAUGE:-1000000:1000000 timeleft timeleft:GAUGE:0:3600 time_offset seconds:GAUGE:-1000000:1000000 +uptime value:GAUGE:0:4294967295 users users:GAUGE:0:65535 virt_cpu_total ns:COUNTER:0:256000000000 virt_vcpu ns:COUNTER:0:1000000000 diff --git a/src/uptime.c b/src/uptime.c new file mode 100644 index 00000000..f98be065 --- /dev/null +++ b/src/uptime.c @@ -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 + **/ + +#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 ? */ +/* + Using kstats chain to retrieve the boot time, this applies to: + - Solaris / OpenSolaris +*/ +/* #endif HAVE_LIBKSTAT */ + +#elif HAVE_SYS_SYSCTL_H +# include +/* + 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 */ -- 2.30.2