diff --git a/common.am b/common.am index c6946da..f0dbfc2 100644 --- a/common.am +++ b/common.am @@ -1,7 +1,9 @@ MANCENTER="Munin C Documentation" RELEASE="$(shell $(top_srcdir)/getversion)" -%.1:%.pod +.pod.1: $(AM_V_GEN)pod2man --section=1 --release=$(RELEASE) --center=$(MANCENTER) $< > $@ +SUFFIXES = .1 .pod + # vim:ft=make diff --git a/configure.ac b/configure.ac index c642204..82ca0a3 100644 --- a/configure.ac +++ b/configure.ac @@ -15,6 +15,16 @@ AM_INIT_AUTOMAKE([foreign subdir-objects]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AM_MAINTAINER_MODE([enable]) +AC_CANONICAL_HOST +case $host in + *bsd* | *darwin* ) + SYS_API='sysctl' ;; + *) + SYS_API='proc' ;; +esac + +AC_SUBST([SYS_API]) + AC_PROG_CC AC_PROG_CC_C_O diff --git a/src/common/xctype.h b/src/common/xctype.h new file mode 100644 index 0000000..fe67da3 --- /dev/null +++ b/src/common/xctype.h @@ -0,0 +1,7 @@ +/* put here extended versions of + * Only use #define tricks to avoid the overhead of func call + */ + +/* Defined by the ctype(3) in NetBSD */ +#define xisdigit(x) isdigit((int)(unsigned char) (x)) +#define xisspace(x) isspace((int)(unsigned char) (x)) diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 4082452..1af5991 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -12,6 +12,7 @@ include $(top_srcdir)/common.am pkglibexec_PROGRAMS = munin-plugins-c munin_plugins_c_SOURCES = \ + load-$(SYS_API).c \ common.c \ common.h \ plugins.h \ @@ -21,7 +22,6 @@ munin_plugins_c_SOURCES = \ fw_packets.c \ if_err_.c \ interrupts.c \ - load.c \ main.c \ open_files.c \ open_inodes.c \ @@ -30,6 +30,7 @@ munin_plugins_c_SOURCES = \ threads.c \ memory.c \ uptime.c + man_MANS = munin-plugins-c.1 CLEANFILES = $(man_MANS) EXTRA_DIST = munin-plugins-c.pod diff --git a/src/plugins/cpu-sysctl.c b/src/plugins/cpu-sysctl.c new file mode 100644 index 0000000..3ea6ead --- /dev/null +++ b/src/plugins/cpu-sysctl.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2015 Steve Schnepp - All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2 or v.3. + */ +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "plugins.h" + +#define SYSWARNING 30 +#define SYSCRITICAL 50 +#define USRWARNING 80 + +/* TODO: port support for env.foo_warning and env.foo_critical from mainline plugin */ + +static int print_stat_value(const char* field_name, const char* stat_value, int hz_) { + return printf("%s.value %llu\n", field_name, strtoull(stat_value, NULL, 0) * 100 / hz_); +} + +int cpu(int argc, char **argv) { + FILE *f; + char buff[256], *s; + int ncpu=0, extinfo=0, hz_; + bool scaleto100 = false; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + s = getenv("scaleto100"); + if(s && !strcmp(s, "yes")) + scaleto100 = true; + + if(!(f=fopen(PROC_STAT, "r"))) + return fail("cannot open " PROC_STAT); + while(fgets(buff, 256, f)) { + if(!strncmp(buff, "cpu", 3)) { + if(isdigit(buff[3])) + ncpu++; + if(buff[3] == ' ' && 0 == extinfo) { + strtok(buff+4, " \t"); + for(extinfo=1;strtok(NULL, " \t");extinfo++) + ; + } + } + } + fclose(f); + + if(ncpu < 1 || extinfo < 4) + return fail("cannot parse " PROC_STAT); + + puts("graph_title CPU usage"); + if(extinfo >= 7) + puts("graph_order system user nice idle iowait irq softirq"); + else + puts("graph_order system user nice idle"); + if(scaleto100) + puts("graph_args --base 1000 -r --lower-limit 0 --upper-limit 100"); + else + printf("graph_args --base 1000 -r --lower-limit 0 --upper-limit %d\n", 100 * ncpu); + puts("graph_vlabel %\n" + "graph_scale no\n" + "graph_info This graph shows how CPU time is spent.\n" + "graph_category system\n" + "graph_period second\n" + "system.label system\n" + "system.draw AREA"); + printf("system.max %d\n", 100 * ncpu); + puts("system.min 0\n" + "system.type DERIVE"); + printf("system.warning %d\n", SYSWARNING * ncpu); + printf("system.critical %d\n", SYSCRITICAL * ncpu); + puts("system.info CPU time spent by the kernel in system activities\n" + "user.label user\n" + "user.draw STACK\n" + "user.min 0"); + printf("user.max %d\n", 100 * ncpu); + printf("user.warning %d\n", USRWARNING * ncpu); + puts("user.type DERIVE\n" + "user.info CPU time spent by normal programs and daemons\n" + "nice.label nice\n" + "nice.draw STACK\n" + "nice.min 0"); + printf("nice.max %d\n", 100 * ncpu); + puts("nice.type DERIVE\n" + "nice.info CPU time spent by nice(1)d programs\n" + "idle.label idle\n" + "idle.draw STACK\n" + "idle.min 0"); + printf("idle.max %d\n", 100 * ncpu); + puts("idle.type DERIVE\n" + "idle.info Idle CPU time"); + if(scaleto100) + printf("system.cdef system,%d,/\n" + "user.cdef user,%d,/\n" + "nice.cdef nice,%d,/\n" + "idle.cdef idle,%d,/\n", ncpu, ncpu, ncpu, ncpu); + if(extinfo >= 7) { + puts("iowait.label iowait\n" + "iowait.draw STACK\n" + "iowait.min 0"); + printf("iowait.max %d\n", 100 * ncpu); + puts("iowait.type DERIVE\n" + "iowait.info CPU time spent waiting for I/O operations to finish\n" + "irq.label irq\n" + "irq.draw STACK\n" + "irq.min 0"); + printf("irq.max %d\n", 100 * ncpu); + puts("irq.type DERIVE\n" + "irq.info CPU time spent handling interrupts\n" + "softirq.label softirq\n" + "softirq.draw STACK\n" + "softirq.min 0"); + printf("softirq.max %d\n", 100 * ncpu); + puts("softirq.type DERIVE\n" + "softirq.info CPU time spent handling \"batched\" interrupts"); + if(scaleto100) + printf("iowait.cdef iowait,%d,/\n" + "irq.cdef irq,%d,/\n" + "softirq.cdef softirq,%d,/\n", ncpu, ncpu, ncpu); + } + if(extinfo >= 8) { + puts("steal.label steal\n" + "steal.draw STACK\n" + "steal.min 0"); + printf("steal.max %d\n", 100 * ncpu); + puts("steal.type DERIVE\n" + "steal.info The time that a virtual CPU had runnable tasks, but the virtual CPU itself was not running"); + if(scaleto100) + printf("steal.cdef steal,%d,/\n", ncpu); + } + if(extinfo >= 9) { + puts("guest.label guest\n" + "guest.draw STACK\n" + "guest.min 0"); + printf("guest.max %d\n", 100 * ncpu); + puts("guest.type DERIVE\n" + "guest.info The time spent running a virtual CPU for guest operating systems under the control of the Linux kernel."); + if(scaleto100) + printf("guest.cdef guest,%d,/\n", ncpu); + } + return 0; + } + if(!strcmp(argv[1], "autoconf")) + return autoconf_check_readable(PROC_STAT); + } + if(!(f=fopen(PROC_STAT, "r"))) + return fail("cannot open " PROC_STAT); + hz_ = getenvint("HZ", 100); + while(fgets(buff, 256, f)) { + if(!strncmp(buff, "cpu ", 4)) { + fclose(f); + if(!(s = strtok(buff+4, " \t"))) + break; + print_stat_value("user", s, hz_); + if(!(s = strtok(NULL, " \t"))) + break; + print_stat_value("nice", s, hz_); + if(!(s = strtok(NULL, " \t"))) + break; + print_stat_value("system", s, hz_); + if(!(s = strtok(NULL, " \t"))) + break; + print_stat_value("idle", s, hz_); + if(!(s = strtok(NULL, " \t"))) + return 0; + print_stat_value("iowait", s, hz_); + if(!(s = strtok(NULL, " \t"))) + return 0; + print_stat_value("irq", s, hz_); + if(!(s = strtok(NULL, " \t"))) + return 0; + print_stat_value("softirq", s, hz_); + if(!(s = strtok(NULL, " \t"))) + return 0; + print_stat_value("steal", s, hz_); + if(!(s = strtok(NULL, " \t"))) + return 0; + print_stat_value("guest", s, hz_); + return 0; + } + } + fclose(f); + return fail("no cpu line found in " PROC_STAT); +} diff --git a/src/plugins/load.c b/src/plugins/load-proc.c similarity index 100% rename from src/plugins/load.c rename to src/plugins/load-proc.c diff --git a/src/plugins/load-sysctl.c b/src/plugins/load-sysctl.c new file mode 100644 index 0000000..472e2a0 --- /dev/null +++ b/src/plugins/load-sysctl.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Steve Schnepp - All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2 or v.3. + */ + +/* This plugin is compatible with munin-mainline version 2.0.25. */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "plugins.h" + +#include + +int load(int argc, char **argv) { + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Load average\n" + "graph_args --base 1000 -l 0\n" + "graph_vlabel load\n" + "graph_scale no\n" + "graph_category system\n" + "load.label load"); + print_warncrit("load"); + puts("graph_info The load average of the machine describes how many processes are in the run-queue (scheduled to run \"immediately\").\n" + "load.info 5 minute load average"); + return 0; + } + if(!strcmp(argv[1], "autoconf")) + return writeyes(); + } + + struct loadavg l; + size_t len = sizeof(l); + + if (sysctlbyname("vm.loadavg", &l, &len, NULL, 0) < 0) { + return fail("sysctl"); + } + + double ldavg = l.ldavg[0]; + double fscale = l.fscale; + + printf("# vm.loadavg, ldavg:%f fscale:%f -", ldavg, fscale); + printf("\n"); + + double load_1 = ldavg / fscale; + printf("load.value %.2f\n", load_1); + return 0; +} diff --git a/src/plugins/memory-sysctl.c b/src/plugins/memory-sysctl.c new file mode 100644 index 0000000..07fb433 --- /dev/null +++ b/src/plugins/memory-sysctl.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015 Steve Schnepp - All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2 or v.3. + */ + +/* This plugin is compatible with munin-mainline version 2.0.25. */ + +#include +#include +#include +#include +#include +#include "common.h" +#include "plugins.h" + +#include + +int memory(int argc, char **argv) { + + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + printf( + "graph_vlabel Bytes\n" + "graph_args --base 1024 -l 0\n" + "graph_title Memory usage\n" + "graph_category system\n" + "graph_info This graph shows what the machine uses memory for.\n" + ); + printf("apps.label apps\n"); + printf("apps.draw AREA\n"); + printf("apps.info Memory used by user-space applications.\n"); + + printf("free.label free\n"); + printf("free.draw STACK\n"); + printf("free.info Wasted memory. Memory that is not used for anything at all.\n"); + + printf("swap.label swap\n"); + printf("swap.draw STACK\n"); + printf("swap.info Swap space used.\n"); + + +if [ "$1" = "config" ]; then + echo 'graph_args --base 1024 -l 0 --vertical-label Bytes --upper-limit' $MEMMAX + echo 'graph_title Memory usage' + echo 'graph_category system' + echo 'graph_info This graph shows what the machine uses its memory for.' + echo 'graph_order active inactive wired cached free swap buffers' + echo 'active.label active' + echo 'active.info pages recently statistically used' + echo 'active.draw AREA' + echo 'inactive.label inactive' + echo 'inactive.info pages recently statistically unused' + echo 'inactive.draw STACK' + echo 'wired.label wired' + echo 'wired.info pages that are fixed into memory, usually for kernel purposes, but also sometimes for special use in processes' + echo 'wired.draw STACK' + echo 'cached.label cache' + echo 'cached.info pages that have percolated from inactive to a status where they maintain their data, but can often be immediately reused' + echo 'cached.draw STACK' + echo 'free.label free' + echo 'free.info pages without data content' + echo 'free.draw STACK' + echo 'swap.label swap' + echo 'swap.info Swap space used' + echo 'swap.draw STACK' + echo 'buffers.label buffers' + echo 'buffers.info pages used for filesystem buffers' + echo 'buffers.draw LINE' + exit 0 +fi + + + + + + + + + + + return 0; + } + if(!strcmp(argv[1], "autoconf")) + return writeyes(); + } + + struct vmtotal s; + size_t len = sizeof(s); + + if (sysctlbyname("vm.total", &s, &len, NULL, 0) < 0) { + return fail("sysctl"); + } + + double ldavg = l.ldavg[0]; + double fscale = l.fscale; + + printf("# vm.loadavg, ldavg:%f fscale:%f -", ldavg, fscale); + printf("\n"); + + double load_1 = ldavg / fscale; + printf("load.value %.2f\n", load_1); + return 0; +}