diff options
author | Holger Weiss <hweiss@users.sourceforge.net> | 2009-04-22 00:28:53 +0200 |
---|---|---|
committer | Holger Weiss <hweiss@users.sourceforge.net> | 2009-04-22 00:47:29 +0200 |
commit | 92bb86c484c3d52c5ffdfa790f7a5acf68edcc36 (patch) | |
tree | e2195501bf3b67b373c9c3ddd0a5f0330d0209ed | |
parent | 05a980ba4bd3de0540771000955bd3235ad17acd (diff) | |
download | monitoring-plugins-92bb86c484c3d52c5ffdfa790f7a5acf68edcc36.tar.gz |
Make C plugin output format configurable
*** THIS COMMIT WILL BE MODIFIED IN THE FUTURE! ***
The development guidelines¹ currently state that the plugin output
should be in the format "SERVICE STATUS: Information text".
However, when a plugin is called via Nagios in order to perform a
service check, adding SERVICE and STATUS to the output is redundant.
And when a plugin is called on the command line for testing, there is no
use in printing out the SERVICE string, either. However, for debugging,
it does make sense to print out the STATUS so that the user won't have
to check and interpret the exit code manually. But it should suffice to
print such debug output only when called with "--verbose", not in
production.
Space for plugin output is sometimes scarce, so that we should try to
keep the output "short and to the point" (as the guide states) and not
waste space with redundant information. Therefore, we decided² to make
the ("normal" and "verbose") plugin output configurable at compile time.
¹ http://nagiosplug.sf.net/developer-guidelines.html
² http://thread.gmane.org/gmane.network.nagios.plugins.devel/5155
-rw-r--r-- | configure.in | 38 | ||||
-rw-r--r-- | lib/utils_base.c | 202 | ||||
-rw-r--r-- | lib/utils_base.h | 19 | ||||
-rw-r--r-- | plugins/utils.c | 17 | ||||
-rw-r--r-- | plugins/utils.h | 2 |
5 files changed, 259 insertions, 19 deletions
diff --git a/configure.in b/configure.in index 9067978a..474522d4 100644 --- a/configure.in +++ b/configure.in | |||
@@ -40,6 +40,39 @@ INSTALL="$INSTALL $extra_install_args" | |||
40 | INSTALL_STRIP_PROGRAM="$INSTALL_STRIP_PROGRAM $extra_install_args" | 40 | INSTALL_STRIP_PROGRAM="$INSTALL_STRIP_PROGRAM $extra_install_args" |
41 | AC_SUBST(INSTALL) | 41 | AC_SUBST(INSTALL) |
42 | 42 | ||
43 | dnl Configure the plugin output format | ||
44 | default_output_format="%s %x: %i\n" | ||
45 | AC_ARG_WITH([standard_output_format], | ||
46 | [AS_HELP_STRING([--with-standard-output-format=FORMAT], | ||
47 | [specify the standard plugin output FORMAT; %p, %s, %x, and %m | ||
48 | will be replaced by the plugin name, the service name, the | ||
49 | status string, and the information message, respectively; tabs | ||
50 | or newlines can be inserted using \t or \n | ||
51 | @<:@default="%s %x: %m\n"@:>@])], | ||
52 | [standard_output_format=$withval], | ||
53 | [standard_output_format="yes"]) | ||
54 | AC_ARG_WITH([verbose_output_format], | ||
55 | [AS_HELP_STRING([--with-verbose-output-format=FORMAT], | ||
56 | [specify the verbose plugin output FORMAT; %p, %s, %x, and %m | ||
57 | will be replaced by the plugin name, the service name, the | ||
58 | status string, and the information message, respectively; tabs | ||
59 | or newlines can be inserted using \t or \n | ||
60 | @<:@default="%s %x: %m\n"@:>@])], | ||
61 | [verbose_output_format=$withval], | ||
62 | [verbose_output_format="yes"]) | ||
63 | AS_IF([test "$standard_output_format" = yes], | ||
64 | [standard_output_format=$default_output_format], | ||
65 | [test "$standard_output_format" = no], | ||
66 | [standard_output_format=""], | ||
67 | [test "$verbose_output_format" = yes], | ||
68 | [verbose_output_format=$default_output_format], | ||
69 | [test "$verbose_output_format" = no], | ||
70 | [verbose_output_format=""]) | ||
71 | AC_DEFINE_UNQUOTED([STANDARD_OUTPUT_FORMAT], ["$standard_output_format"], | ||
72 | [Define the standard plugin output format.]) | ||
73 | AC_DEFINE_UNQUOTED([VERBOSE_OUTPUT_FORMAT], ["$verbose_output_format"], | ||
74 | [Define the verbose plugin output format.]) | ||
75 | |||
43 | AC_PROG_CC | 76 | AC_PROG_CC |
44 | gl_EARLY | 77 | gl_EARLY |
45 | AC_PROG_GCC_TRADITIONAL | 78 | AC_PROG_GCC_TRADITIONAL |
@@ -147,6 +180,11 @@ AC_CHECK_LIB(socket,socket,SOCKETLIBS="$SOCKETLIBS -lsocket") | |||
147 | AC_CHECK_LIB(resolv,main,SOCKETLIBS="$SOCKETLIBS -lresolv") | 180 | AC_CHECK_LIB(resolv,main,SOCKETLIBS="$SOCKETLIBS -lresolv") |
148 | AC_SUBST(SOCKETLIBS) | 181 | AC_SUBST(SOCKETLIBS) |
149 | 182 | ||
183 | dnl check for basename(3) which needs -lgen on some systems (e.g. IRIX) | ||
184 | AC_CHECK_HEADERS([libgen.h]) | ||
185 | AC_SEARCH_LIBS([basename], [gen]) | ||
186 | AC_CHECK_FUNCS([basename]) | ||
187 | |||
150 | dnl | 188 | dnl |
151 | dnl check for math-related functions needing -lm | 189 | dnl check for math-related functions needing -lm |
152 | AC_CHECK_HEADERS(math.h) | 190 | AC_CHECK_HEADERS(math.h) |
diff --git a/lib/utils_base.c b/lib/utils_base.c index fbed3607..7eada0cc 100644 --- a/lib/utils_base.c +++ b/lib/utils_base.c | |||
@@ -12,10 +12,150 @@ | |||
12 | * $Date$ | 12 | * $Date$ |
13 | ****************************************************************************/ | 13 | ****************************************************************************/ |
14 | 14 | ||
15 | #if HAVE_LIBGEN_H | ||
16 | #include <libgen.h> /* basename(3) */ | ||
17 | #endif | ||
15 | #include <stdarg.h> | 18 | #include <stdarg.h> |
16 | #include "common.h" | 19 | #include "common.h" |
17 | #include "utils_base.h" | 20 | #include "utils_base.h" |
18 | 21 | ||
22 | #define PRINT_OUTPUT(fmt, ap) \ | ||
23 | do { \ | ||
24 | fmt = insert_syserr(fmt); \ | ||
25 | va_start(ap, fmt); \ | ||
26 | vprintf(fmt, ap); \ | ||
27 | va_end(ap); \ | ||
28 | } while (/* CONSTCOND */ 0) | ||
29 | |||
30 | static char *insert_syserr(const char *); | ||
31 | |||
32 | extern int errno; | ||
33 | static int verbosity_level = -2; | ||
34 | static const char *program_name = NULL; | ||
35 | static const char *service_name = NULL; | ||
36 | |||
37 | /* | ||
38 | * Set static variables for use in output functions. Usually, argv[0] may be | ||
39 | * used as progname, since we call basename(3) ourselves. If a verbosity value | ||
40 | * of -2 is specified, the verbosity_level won't be set. Currently, no flags | ||
41 | * are implemented. | ||
42 | */ | ||
43 | void | ||
44 | np_set_output(const char *progname, const char *servname, int verbosity, | ||
45 | int flags __attribute__((unused))) | ||
46 | { | ||
47 | static char pathbuf[128], progbuf[128], servbuf[32]; | ||
48 | |||
49 | if (progname != NULL) { | ||
50 | #if HAVE_BASENAME | ||
51 | /* | ||
52 | * Copy the progname into a temporary buffer in order to cope | ||
53 | * with basename(3) implementations which modify their argument. | ||
54 | * TODO: Maybe we should implement an np_basename()? Gnulib's | ||
55 | * base_name() dies on error, writing a message to stderr, which | ||
56 | * is probably not what we want. Once we have some replacement, | ||
57 | * the libgen-/basename(3)-related checks can be removed from | ||
58 | * configure.in. | ||
59 | */ | ||
60 | strncpy(pathbuf, progname, sizeof(pathbuf) - 1); | ||
61 | pathbuf[sizeof(pathbuf) - 1] = '\0'; | ||
62 | progname = basename(pathbuf); | ||
63 | #endif | ||
64 | strncpy(progbuf, progname, sizeof(progbuf) - 1); | ||
65 | progbuf[sizeof(progbuf) - 1] = '\0'; | ||
66 | program_name = progbuf; | ||
67 | } | ||
68 | if (servname != NULL) { | ||
69 | strncpy(servbuf, servname, sizeof(servbuf) - 1); | ||
70 | servbuf[sizeof(servbuf) - 1] = '\0'; | ||
71 | service_name = servbuf; | ||
72 | } | ||
73 | if (verbosity != -2) | ||
74 | verbosity_level = verbosity; | ||
75 | } | ||
76 | |||
77 | int | ||
78 | np_adjust_verbosity(int by) | ||
79 | { | ||
80 | if (verbosity_level == -2) | ||
81 | verbosity_level = by; | ||
82 | else | ||
83 | verbosity_level += by; | ||
84 | |||
85 | /* We don't support verbosity levels < -1. */ | ||
86 | if (verbosity_level < -1) | ||
87 | verbosity_level = -1; | ||
88 | |||
89 | return verbosity_level; | ||
90 | } | ||
91 | |||
92 | void | ||
93 | np_debug(int verbosity, const char *fmt, ...) | ||
94 | { | ||
95 | va_list ap; | ||
96 | |||
97 | if (verbosity_level != -1 && verbosity >= verbosity_level) | ||
98 | PRINT_OUTPUT(fmt, ap); | ||
99 | } | ||
100 | |||
101 | void | ||
102 | np_verbose(const char *fmt, ...) | ||
103 | { | ||
104 | va_list ap; | ||
105 | |||
106 | if (verbosity_level >= 1) { | ||
107 | PRINT_OUTPUT(fmt, ap); | ||
108 | putchar('\n'); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | void | ||
113 | np_die(int status, const char *fmt, ...) | ||
114 | { | ||
115 | va_list ap; | ||
116 | const char *p; | ||
117 | |||
118 | if (program_name == NULL || service_name == NULL) | ||
119 | PRINT_OUTPUT(fmt, ap); | ||
120 | |||
121 | for (p = (verbosity_level > 0) ? | ||
122 | VERBOSE_OUTPUT_FORMAT : STANDARD_OUTPUT_FORMAT; | ||
123 | *p != '\0'; p++) { | ||
124 | if (*p == '%') { | ||
125 | if (*++p == '\0') | ||
126 | break; | ||
127 | switch (*p) { | ||
128 | case 'm': | ||
129 | PRINT_OUTPUT(fmt, ap); | ||
130 | continue; | ||
131 | case 'p': | ||
132 | fputs(program_name, stdout); | ||
133 | continue; | ||
134 | case 's': | ||
135 | fputs(service_name, stdout); | ||
136 | continue; | ||
137 | case 'x': | ||
138 | fputs(state_text(status), stdout); | ||
139 | continue; | ||
140 | } | ||
141 | } else if (*p == '\\') { | ||
142 | if (*++p == '\0') | ||
143 | break; | ||
144 | switch (*p) { | ||
145 | case 'n': | ||
146 | putchar('\n'); | ||
147 | continue; | ||
148 | case 't': | ||
149 | putchar('\t'); | ||
150 | continue; | ||
151 | } | ||
152 | } | ||
153 | putchar(*p); | ||
154 | } | ||
155 | exit(status); | ||
156 | } | ||
157 | |||
158 | /* TODO: die() can be removed as soon as all plugins use np_die() instead. */ | ||
19 | void | 159 | void |
20 | die (int result, const char *fmt, ...) | 160 | die (int result, const char *fmt, ...) |
21 | { | 161 | { |
@@ -243,3 +383,65 @@ int np_warn_if_not_root(void) { | |||
243 | } | 383 | } |
244 | return status; | 384 | return status; |
245 | } | 385 | } |
386 | |||
387 | const char * | ||
388 | state_text(int result) | ||
389 | { | ||
390 | switch (result) { | ||
391 | case STATE_OK: | ||
392 | return "OK"; | ||
393 | case STATE_WARNING: | ||
394 | return "WARNING"; | ||
395 | case STATE_CRITICAL: | ||
396 | return "CRITICAL"; | ||
397 | case STATE_DEPENDENT: | ||
398 | return "DEPENDENT"; | ||
399 | default: | ||
400 | return "UNKNOWN"; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Replace occurrences of "%m" by strerror(errno). Other printf(3)-style | ||
406 | * conversion specifications will be copied verbatim, including "%%", even if | ||
407 | * followed by an "m". Returns a static buffer in order to not fail on memory | ||
408 | * allocation error. | ||
409 | */ | ||
410 | static char * | ||
411 | insert_syserr(const char *buf) | ||
412 | { | ||
413 | static char newbuf[8192]; | ||
414 | char *errstr = strerror(errno); | ||
415 | size_t errlen = strlen(errstr); | ||
416 | size_t copylen; | ||
417 | unsigned i, j; | ||
418 | |||
419 | for (i = 0, j = 0; buf[i] != '\0' && j < sizeof(newbuf) - 2; i++, j++) { | ||
420 | if (buf[i] == '%') { | ||
421 | if (buf[++i] == 'm') { | ||
422 | copylen = (errlen > sizeof(newbuf) - j - 1) ? | ||
423 | sizeof(newbuf) - j - 1 : errlen; | ||
424 | memcpy(newbuf + j, errstr, copylen); | ||
425 | /* | ||
426 | * As we'll increment j by 1 after the iteration | ||
427 | * anyway, we only increment j by the number of | ||
428 | * copied bytes - 1. | ||
429 | */ | ||
430 | j += copylen - 1; | ||
431 | continue; | ||
432 | } else { | ||
433 | /* | ||
434 | * The possibility to run into this block is the | ||
435 | * reason we checked for j < sizeof(newbuf) - 2 | ||
436 | * instead of j < sizeof(newbuf) - 1. | ||
437 | */ | ||
438 | newbuf[j++] = '%'; | ||
439 | if (buf[i] == '\0') | ||
440 | break; | ||
441 | } | ||
442 | } | ||
443 | newbuf[j] = buf[i]; | ||
444 | } | ||
445 | newbuf[j] = '\0'; | ||
446 | return newbuf; | ||
447 | } | ||
diff --git a/lib/utils_base.h b/lib/utils_base.h index bda76595..b6e8128b 100644 --- a/lib/utils_base.h +++ b/lib/utils_base.h | |||
@@ -37,6 +37,23 @@ int get_status(double, thresholds *); | |||
37 | 37 | ||
38 | char *np_escaped_string (const char *); | 38 | char *np_escaped_string (const char *); |
39 | 39 | ||
40 | void np_set_output(const char *, const char *, int, int); | ||
41 | int np_adjust_verbosity(int); | ||
42 | void np_debug(int, const char *, ...) | ||
43 | __attribute__((format(printf, 2, 3))); | ||
44 | void np_verbose(const char *, ...) | ||
45 | __attribute__((format(printf, 1, 2))); | ||
46 | void np_die(int, const char *, ...) | ||
47 | __attribute__((noreturn, format(printf, 2, 3))); | ||
48 | |||
49 | #define np_verbatim(s) np_verbose("%s", s) | ||
50 | #define np_increase_verbosity(i) np_adjust_verbosity(i) | ||
51 | #define np_decrease_verbosity(i) np_adjust_verbosity(-i) | ||
52 | #define np_get_verbosity() np_adjust_verbosity(0) | ||
53 | #define np_set_verbosity(v) np_set_output(NULL, NULL, v, 0) | ||
54 | #define np_set_mynames(p, s) np_set_output(p, s, -2, 0) | ||
55 | |||
56 | /* TODO: die() can be removed as soon as all plugins use np_die() instead. */ | ||
40 | void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); | 57 | void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); |
41 | 58 | ||
42 | /* Return codes for _set_thresholds */ | 59 | /* Return codes for _set_thresholds */ |
@@ -50,4 +67,6 @@ int np_check_if_root(void); | |||
50 | * code from the above function, in case it's helpful for testing */ | 67 | * code from the above function, in case it's helpful for testing */ |
51 | int np_warn_if_not_root(void); | 68 | int np_warn_if_not_root(void); |
52 | 69 | ||
70 | const char *state_text(int); | ||
71 | |||
53 | #endif /* _UTILS_BASE_ */ | 72 | #endif /* _UTILS_BASE_ */ |
diff --git a/plugins/utils.c b/plugins/utils.c index 0e79fbdb..5967647a 100644 --- a/plugins/utils.c +++ b/plugins/utils.c | |||
@@ -121,23 +121,6 @@ print_revision (const char *command_name, const char *revision_string) | |||
121 | command_name, clean_revstring(revision_string), PACKAGE, VERSION); | 121 | command_name, clean_revstring(revision_string), PACKAGE, VERSION); |
122 | } | 122 | } |
123 | 123 | ||
124 | const char * | ||
125 | state_text (int result) | ||
126 | { | ||
127 | switch (result) { | ||
128 | case STATE_OK: | ||
129 | return "OK"; | ||
130 | case STATE_WARNING: | ||
131 | return "WARNING"; | ||
132 | case STATE_CRITICAL: | ||
133 | return "CRITICAL"; | ||
134 | case STATE_DEPENDENT: | ||
135 | return "DEPENDENT"; | ||
136 | default: | ||
137 | return "UNKNOWN"; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | void | 124 | void |
142 | timeout_alarm_handler (int signo) | 125 | timeout_alarm_handler (int signo) |
143 | { | 126 | { |
diff --git a/plugins/utils.h b/plugins/utils.h index f15a7b16..98d19d20 100644 --- a/plugins/utils.h +++ b/plugins/utils.h | |||
@@ -84,8 +84,6 @@ void usage4(const char *) __attribute__((noreturn)); | |||
84 | void usage5(void) __attribute__((noreturn)); | 84 | void usage5(void) __attribute__((noreturn)); |
85 | void usage_va(const char *fmt, ...) __attribute__((noreturn)); | 85 | void usage_va(const char *fmt, ...) __attribute__((noreturn)); |
86 | 86 | ||
87 | const char *state_text (int); | ||
88 | |||
89 | #define max(a,b) (((a)>(b))?(a):(b)) | 87 | #define max(a,b) (((a)>(b))?(a):(b)) |
90 | #define min(a,b) (((a)<(b))?(a):(b)) | 88 | #define min(a,b) (((a)<(b))?(a):(b)) |
91 | 89 | ||