Merge branch 'collectd-4.10' into collectd-5.0
[collectd.git] / src / collectd-nagios.c
index f37f78d..af8744d 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd-nagios - src/collectd-nagios.c
- * Copyright (C) 2008  Florian octo Forster
+ * Copyright (C) 2008-2010  Florian octo Forster
  *
  * 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
  *   Florian octo Forster <octo at verplant.org>
  **/
 
-/* Set to C99 and POSIX code */
-#ifndef _ISOC99_SOURCE
-# define _ISOC99_SOURCE
-#endif
-#ifndef _POSIX_SOURCE
-# define _POSIX_SOURCE
-#endif
-#ifndef _POSIX_C_SOURCE
-# define _POSIX_C_SOURCE 200112L
-#endif
-#ifndef _REENTRANT
-# define _REENTRANT
-#endif
-
-/* Disable non-standard extensions */
-#ifdef _BSD_SOURCE
-# undef _BSD_SOURCE
-#endif
-#ifdef _SVID_SOURCE
-# undef _SVID_SOURCE
-#endif
-#ifdef _GNU_SOURCE
-# undef _GNU_SOURCE
+#if HAVE_CONFIG_H
+# include "config.h"
 #endif
 
 #if !defined(__GNUC__) || !__GNUC__
 # define __attribute__(x) /**/
 #endif
 
-#include "config.h"
-
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <strings.h>
 #include <assert.h>
 
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "libcollectdclient/client.h"
-
-/*
- * This is copied directly from collectd.h. Make changes there!
- */
 #if NAN_STATIC_DEFAULT
 # include <math.h>
 /* #endif NAN_STATIC_DEFAULT*/
 # ifndef isnan
 #  define isnan(f) ((f) != (f))
 # endif /* !defined(isnan) */
+# ifndef isfinite
+#  define isfinite(f) (((f) - (f)) == 0.0)
+# endif
+# ifndef isinf
+#  define isinf(f) (!isfinite(f) && !isnan(f))
+# endif
 #endif /* NAN_ZERO_ZERO */
 
+#include "libcollectdclient/client.h"
+
 #define RET_OKAY     0
 #define RET_WARNING  1
 #define RET_CRITICAL 2
@@ -99,6 +76,7 @@
 #define CON_NONE     0
 #define CON_AVERAGE  1
 #define CON_SUM      2
+#define CON_PERCENTAGE  3
 
 struct range_s
 {
@@ -118,6 +96,7 @@ static char *hostname_g = NULL;
 static range_t range_critical_g;
 static range_t range_warning_g;
 static int consolitation_g = CON_NONE;
+static _Bool nan_is_error_g = 0;
 
 static char **match_ds_g = NULL;
 static int    match_ds_num_g = 0;
@@ -164,7 +143,7 @@ static int filter_ds (size_t *values_num,
                return (RET_UNKNOWN);
        }
 
-       for (i = 0; i < match_ds_num_g; i++)
+       for (i = 0; i < (size_t) match_ds_num_g; i++)
        {
                size_t j;
 
@@ -272,10 +251,11 @@ static void usage (const char *name)
                        "  -d <ds>        Select the DS to examine. May be repeated to examine multiple\n"
                        "                 DSes. By default all DSes are used.\n"
                        "  -g <consol>    Method to use to consolidate several DSes.\n"
-                       "                 Valid arguments are `none', `average' and `sum'\n"
+                       "                 See below for a list of valid arguments.\n"
                        "  -H <host>      Hostname to query the values for.\n"
                        "  -c <range>     Critical range\n"
                        "  -w <range>     Warning range\n"
+                       "  -m             Treat \"Not a Number\" (NaN) as critical (default: warning)\n"
                        "\n"
                        "Consolidation functions:\n"
                        "  none:          Apply the warning- and critical-ranges to each data-source\n"
@@ -283,6 +263,8 @@ static void usage (const char *name)
                        "  average:       Calculate the average of all matching DSes and apply the\n"
                        "                 warning- and critical-ranges to the calculated average.\n"
                        "  sum:           Apply the ranges to the sum of all DSes.\n"
+                       "  percentage:    Apply the ranges to the ratio (in percent) of the first value\n"
+                       "                 and the sum of all values."
                        "\n", name);
        exit (1);
 } /* void usage */
@@ -295,12 +277,17 @@ static int do_check_con_none (size_t values_num,
        int num_okay = 0;
        const char *status_str = "UNKNOWN";
        int status_code = RET_UNKNOWN;
-       int i;
+       size_t i;
 
        for (i = 0; i < values_num; i++)
        {
                if (isnan (values[i]))
-                       num_warning++;
+               {
+                       if (nan_is_error_g)
+                               num_critical++;
+                       else
+                               num_warning++;
+               }
                else if (match_range (&range_critical_g, values[i]) != 0)
                        num_critical++;
                else if (match_range (&range_warning_g, values[i]) != 0)
@@ -336,7 +323,7 @@ static int do_check_con_none (size_t values_num,
        {
                printf (" |");
                for (i = 0; i < values_num; i++)
-                       printf (" %s=%g;;;;", values_names[i], values[i]);
+                       printf (" %s=%f;;;;", values_names[i], values[i]);
        }
        printf ("\n");
 
@@ -346,7 +333,7 @@ static int do_check_con_none (size_t values_num,
 static int do_check_con_average (size_t values_num,
                double *values, char **values_names)
 {
-       int i;
+       size_t i;
        double total;
        int total_num;
        double average;
@@ -357,11 +344,18 @@ static int do_check_con_average (size_t values_num,
        total_num = 0;
        for (i = 0; i < values_num; i++)
        {
-               if (!isnan (values[i]))
+               if (isnan (values[i]))
                {
-                       total += values[i];
-                       total_num++;
+                       if (!nan_is_error_g)
+                               continue;
+
+                       printf ("CRITICAL: Data source \"%s\" is NaN\n",
+                                       values_names[i]);
+                       return (RET_CRITICAL);
                }
+
+               total += values[i];
+               total_num++;
        }
 
        if (total_num == 0)
@@ -390,7 +384,7 @@ static int do_check_con_average (size_t values_num,
 
        printf ("%s: %g average |", status_str, average);
        for (i = 0; i < values_num; i++)
-               printf (" %s=%g;;;;", values_names[i], values[i]);
+               printf (" %s=%f;;;;", values_names[i], values[i]);
        printf ("\n");
 
        return (status_code);
@@ -399,7 +393,7 @@ static int do_check_con_average (size_t values_num,
 static int do_check_con_sum (size_t values_num,
                double *values, char **values_names)
 {
-       int i;
+       size_t i;
        double total;
        int total_num;
        const char *status_str = "UNKNOWN";
@@ -409,11 +403,18 @@ static int do_check_con_sum (size_t values_num,
        total_num = 0;
        for (i = 0; i < values_num; i++)
        {
-               if (!isnan (values[i]))
+               if (isnan (values[i]))
                {
-                       total += values[i];
-                       total_num++;
+                       if (!nan_is_error_g)
+                               continue;
+
+                       printf ("CRITICAL: Data source \"%s\" is NaN\n",
+                                       values_names[i]);
+                       return (RET_CRITICAL);
                }
+
+               total += values[i];
+               total_num++;
        }
 
        if (total_num == 0)
@@ -440,12 +441,73 @@ static int do_check_con_sum (size_t values_num,
 
        printf ("%s: %g sum |", status_str, total);
        for (i = 0; i < values_num; i++)
-               printf (" %s=%g;;;;", values_names[i], values[i]);
+               printf (" %s=%f;;;;", values_names[i], values[i]);
        printf ("\n");
 
        return (status_code);
 } /* int do_check_con_sum */
 
+static int do_check_con_percentage (size_t values_num,
+               double *values, char **values_names)
+{
+       size_t i;
+       double sum = 0.0;
+       double percentage;
+
+       const char *status_str  = "UNKNOWN";
+       int         status_code = RET_UNKNOWN;
+
+       if ((values_num < 1) || (isnan (values[0])))
+       {
+               printf ("WARNING: The first value is not defined\n");
+               return (RET_WARNING);
+       }
+
+       for (i = 0; i < values_num; i++)
+       {
+               if (isnan (values[i]))
+               {
+                       if (!nan_is_error_g)
+                               continue;
+
+                       printf ("CRITICAL: Data source \"%s\" is NaN\n",
+                                       values_names[i]);
+                       return (RET_CRITICAL);
+               }
+
+               sum += values[i];
+       }
+
+       if (sum == 0.0)
+       {
+               printf ("WARNING: Values sum up to zero\n");
+               return (RET_WARNING);
+       }
+
+       percentage = 100.0 * values[0] / sum;
+
+       if (match_range (&range_critical_g, percentage) != 0)
+       {
+               status_str  = "CRITICAL";
+               status_code = RET_CRITICAL;
+       }
+       else if (match_range (&range_warning_g, percentage) != 0)
+       {
+               status_str  = "WARNING";
+               status_code = RET_WARNING;
+       }
+       else
+       {
+               status_str  = "OKAY";
+               status_code = RET_OKAY;
+       }
+
+       printf ("%s: %lf percent |", status_str, percentage);
+       for (i = 0; i < values_num; i++)
+               printf (" %s=%lf;;;;", values_names[i], values[i]);
+       return (status_code);
+} /* int do_check_con_percentage */
+
 static int do_check (void)
 {
        lcc_connection_t *connection;
@@ -507,6 +569,8 @@ static int do_check (void)
                status =  do_check_con_average (values_num, values, values_names);
        else if (consolitation_g == CON_SUM)
                status = do_check_con_sum (values_num, values, values_names);
+       else if (consolitation_g == CON_PERCENTAGE)
+               status = do_check_con_percentage (values_num, values, values_names);
 
        free (values);
        if (values_names != NULL)
@@ -531,7 +595,7 @@ int main (int argc, char **argv)
        {
                int c;
 
-               c = getopt (argc, argv, "w:c:s:n:H:g:d:h");
+               c = getopt (argc, argv, "w:c:s:n:H:g:d:hm");
                if (c < 0)
                        break;
 
@@ -559,8 +623,14 @@ int main (int argc, char **argv)
                                        consolitation_g = CON_AVERAGE;
                                else if (strcasecmp (optarg, "sum") == 0)
                                        consolitation_g = CON_SUM;
+                               else if (strcasecmp (optarg, "percentage") == 0)
+                                       consolitation_g = CON_PERCENTAGE;
                                else
+                               {
+                                       fprintf (stderr, "Unknown consolidation function `%s'.\n",
+                                                       optarg);
                                        usage (argv[0]);
+                               }
                                break;
                        case 'd':
                        {
@@ -585,6 +655,9 @@ int main (int argc, char **argv)
                                match_ds_num_g++;
                                break;
                        }
+                       case 'm':
+                               nan_is_error_g = 1;
+                               break;
                        default:
                                usage (argv[0]);
                } /* switch (c) */
@@ -592,7 +665,10 @@ int main (int argc, char **argv)
 
        if ((socket_file_g == NULL) || (value_string_g == NULL)
                        || (hostname_g == NULL))
+       {
+               fprintf (stderr, "Missing required arguments.\n");
                usage (argv[0]);
+       }
 
        return (do_check ());
 } /* int main */