1 /******************************************************************************
2 *
3 * Program: MRTG (Multi-Router Traffic Grapher) generic plugin for Nagios
4 * License: GPL
5 *
6 * License Information:
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * $Id$
23 *
24 *****************************************************************************/
26 const char *progname = "check_mrtg";
27 #define REVISION "$Revision$"
28 #define COPYRIGHT "Copyright (c) 1999-2001 Ethan Galstad"
30 #define SUMMARY "\
31 This plugin will check either the average or maximum value of one of the\n\
32 two variables recorded in an MRTG log file.\n"
34 /* old command line:
35 <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */
36 #define OPTIONS "\
37 -F log_file -a <AVG | MAX> -v variable -w warning -c critical\n\
38 [-l label] [-u units] [-e expire_minutes] [-t timeout] [-v]"
40 #define LONGOPTIONS "\
41 -F, --logfile=FILE\n\
42 The MRTG log file containing the data you want to monitor\n\
43 -e, --expires=MINUTES\n\
44 Minutes before MRTG data is considered to be too old\n\
45 -a, --aggregation=AVG|MAX\n\
46 Should we check average or maximum values?\n\
47 -v, --variable=INTEGER\n\
48 Which variable set should we inspect? 1 or 2?\n\
49 -w, --warning=INTEGER\n\
50 Threshold value for data to result in WARNING status\n\
51 -c, --critical=INTEGER\n\
52 Threshold value for data to result in CRITICAL status\n\
53 -l, --label=STRING\n\
54 Type label for data (Examples: Conns, \"Processor Load\", In, Out)\n\
55 -u, --units=STRING\n\
56 Option units label for data (Example: Packets/Sec, Errors/Sec, \n\
57 \"Bytes Per Second\", \"%% Utilization\")\n\
58 -h, --help\n\
59 Print detailed help screen\n\
60 -V, --version\n\
61 Print version information\n"
63 #define DESCRIPTION "\
64 If the value exceeds the <vwl> threshold, a WARNING status is returned. If\n\
65 the value exceeds the <vcl> threshold, a CRITICAL status is returned. If\n\
66 the data in the log file is older than <expire_minutes> old, a WARNING\n\
67 status is returned and a warning message is printed.\n\
68 \n\
69 This plugin is useful for monitoring MRTG data that does not correspond to\n\
70 bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth).\n\
71 It can be used to monitor any kind of data that MRTG is monitoring - errors,\n\
72 packets/sec, etc. I use MRTG in conjuction with the Novell NLM that allows\n\
73 me to track processor utilization, user connections, drive space, etc and\n\
74 this plugin works well for monitoring that kind of data as well.\n\
75 \n\
76 Notes:\n\
77 - This plugin only monitors one of the two variables stored in the MRTG log\n\
78 file. If you want to monitor both values you will have to define two\n\
79 commands with different values for the <variable> argument. Of course,\n\
80 you can always hack the code to make this plugin work for you...\n\
81 - MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from\n\
82 http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html\n"
84 #include "config.h"
85 #include "common.h"
86 #include "utils.h"
88 int process_arguments (int, char **);
89 int validate_arguments (void);
90 void print_help (void);
91 void print_usage (void);
93 char *log_file = NULL;
94 int expire_minutes = 0;
95 int use_average = TRUE;
96 int variable_number = -1;
97 unsigned long value_warning_threshold = 0L;
98 unsigned long value_critical_threshold = 0L;
99 char *value_label = "";
100 char *units_label = "";
102 int
103 main (int argc, char **argv)
104 {
105 int result = STATE_OK;
106 FILE *fp;
107 int line;
108 char input_buffer[MAX_INPUT_BUFFER];
109 char *temp_buffer;
110 time_t current_time;
111 char error_message[MAX_INPUT_BUFFER];
112 time_t timestamp = 0L;
113 unsigned long average_value_rate = 0L;
114 unsigned long maximum_value_rate = 0L;
115 unsigned long value_rate = 0L;
117 if (process_arguments (argc, argv) != OK)
118 usage ("Invalid command arguments supplied\n");
120 /* open the MRTG log file for reading */
121 fp = fopen (log_file, "r");
122 if (fp == NULL) {
123 printf ("Unable to open MRTG log file\n");
124 return STATE_UNKNOWN;
125 }
127 line = 0;
128 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
130 line++;
132 /* skip the first line of the log file */
133 if (line == 1)
134 continue;
136 /* break out of read loop if we've passed the number of entries we want to read */
137 if (line > 2)
138 break;
140 /* grab the timestamp */
141 temp_buffer = strtok (input_buffer, " ");
142 timestamp = strtoul (temp_buffer, NULL, 10);
144 /* grab the average value 1 rate */
145 temp_buffer = strtok (NULL, " ");
146 if (variable_number == 1)
147 average_value_rate = strtoul (temp_buffer, NULL, 10);
149 /* grab the average value 2 rate */
150 temp_buffer = strtok (NULL, " ");
151 if (variable_number == 2)
152 average_value_rate = strtoul (temp_buffer, NULL, 10);
154 /* grab the maximum value 1 rate */
155 temp_buffer = strtok (NULL, " ");
156 if (variable_number == 1)
157 maximum_value_rate = strtoul (temp_buffer, NULL, 10);
159 /* grab the maximum value 2 rate */
160 temp_buffer = strtok (NULL, " ");
161 if (variable_number == 2)
162 maximum_value_rate = strtoul (temp_buffer, NULL, 10);
163 }
165 /* close the log file */
166 fclose (fp);
168 /* if we couldn't read enough data, return an unknown error */
169 if (line <= 2) {
170 result = STATE_UNKNOWN;
171 sprintf (error_message, "Unable to process MRTG log file\n");
172 }
174 /* make sure the MRTG data isn't too old */
175 if (result == STATE_OK) {
176 time (¤t_time);
177 if (expire_minutes > 0
178 && (current_time - timestamp) > (expire_minutes * 60)) {
179 result = STATE_WARNING;
180 sprintf (error_message, "MRTG data has expired (%d minutes old)\n",
181 (int) ((current_time - timestamp) / 60));
182 }
183 }
185 /* else check the incoming/outgoing rates */
186 if (result == STATE_OK) {
188 if (use_average == TRUE)
189 value_rate = average_value_rate;
190 else
191 value_rate = maximum_value_rate;
193 if (value_rate > value_critical_threshold)
194 result = STATE_CRITICAL;
195 else if (value_rate > value_warning_threshold)
196 result = STATE_WARNING;
197 }
199 sprintf (error_message, "%s. %s = %lu %s",
200 (use_average == TRUE) ? "Ave" : "Max", value_label, value_rate,
201 units_label);
202 printf ("%s\n", error_message);
204 return result;
205 }
211 /* process command-line arguments */
212 int
213 process_arguments (int argc, char **argv)
214 {
215 int c;
217 #ifdef HAVE_GETOPT_H
218 int option_index = 0;
219 static struct option long_options[] = {
220 {"logfile", required_argument, 0, 'F'},
221 {"expires", required_argument, 0, 'e'},
222 {"aggregation", required_argument, 0, 'a'},
223 {"variable", required_argument, 0, 'v'},
224 {"critical", required_argument, 0, 'c'},
225 {"warning", required_argument, 0, 'w'},
226 {"label", required_argument, 0, 'l'},
227 {"units", required_argument, 0, 'u'},
228 {"verbose", no_argument, 0, 'v'},
229 {"version", no_argument, 0, 'V'},
230 {"help", no_argument, 0, 'h'},
231 {0, 0, 0, 0}
232 };
233 #endif
235 if (argc < 2)
236 return ERROR;
238 for (c = 1; c < argc; c++) {
239 if (strcmp ("-to", argv[c]) == 0)
240 strcpy (argv[c], "-t");
241 else if (strcmp ("-wt", argv[c]) == 0)
242 strcpy (argv[c], "-w");
243 else if (strcmp ("-ct", argv[c]) == 0)
244 strcpy (argv[c], "-c");
245 }
247 while (1) {
248 #ifdef HAVE_GETOPT_H
249 c =
250 getopt_long (argc, argv, "hVF:e:a:v:c:w:l:u:", long_options,
251 &option_index);
252 #else
253 c = getopt (argc, argv, "hVF:e:a:v:c:w:l:u:");
254 #endif
256 if (c == -1 || c == EOF)
257 break;
259 switch (c) {
260 case 'F': /* input file */
261 log_file = optarg;
262 break;
263 case 'e': /* ups name */
264 expire_minutes = atoi (optarg);
265 break;
266 case 'a': /* port */
267 if (!strcmp (optarg, "MAX"))
268 use_average = FALSE;
269 else
270 use_average = TRUE;
271 break;
272 case 'v':
273 variable_number = atoi (optarg);
274 if (variable_number < 1 || variable_number > 2)
275 usage ("Invalid variable number\n");
276 break;
277 case 'w': /* critical time threshold */
278 value_warning_threshold = strtoul (optarg, NULL, 10);
279 break;
280 case 'c': /* warning time threshold */
281 value_critical_threshold = strtoul (optarg, NULL, 10);
282 break;
283 case 'l': /* label */
284 value_label = optarg;
285 break;
286 case 'u': /* timeout */
287 units_label = optarg;
288 break;
289 case 'V': /* version */
290 print_revision (progname, REVISION);
291 exit (STATE_OK);
292 case 'h': /* help */
293 print_help ();
294 exit (STATE_OK);
295 case '?': /* help */
296 usage ("Invalid argument\n");
297 }
298 }
300 c = optind;
301 if (log_file == NULL && argc > c) {
302 log_file = argv[c++];
303 }
305 if (expire_minutes <= 0 && argc > c) {
306 if (is_intpos (argv[c]))
307 expire_minutes = atoi (argv[c++]);
308 else
309 terminate (STATE_UNKNOWN,
310 "%s is not a valid expiration time\nUse '%s -h' for additional help\n",
311 argv[c], progname);
312 }
314 if (argc > c && strcmp (argv[c], "MAX") == 0) {
315 use_average = FALSE;
316 c++;
317 }
318 else if (argc > c && strcmp (argv[c], "AVG") == 0) {
319 use_average = TRUE;
320 c++;
321 }
323 if (argc > c && variable_number == -1) {
324 variable_number = atoi (argv[c++]);
325 if (variable_number < 1 || variable_number > 2) {
326 printf ("%s :", argv[c]);
327 usage ("Invalid variable number\n");
328 }
329 }
331 if (argc > c && value_warning_threshold == 0) {
332 value_warning_threshold = strtoul (argv[c++], NULL, 10);
333 }
335 if (argc > c && value_critical_threshold == 0) {
336 value_critical_threshold = strtoul (argv[c++], NULL, 10);
337 }
339 if (argc > c && strlen (value_label) == 0) {
340 value_label = argv[c++];
341 }
343 if (argc > c && strlen (units_label) == 0) {
344 units_label = argv[c++];
345 }
347 return validate_arguments ();
348 }
350 int
351 validate_arguments (void)
352 {
353 if (variable_number == -1)
354 usage ("You must supply the variable number\n");
356 return OK;
357 }
359 void
360 print_help (void)
361 {
362 print_revision (progname, REVISION);
363 printf ("%s\n\n%s\n", COPYRIGHT, SUMMARY);
364 print_usage ();
365 printf ("\nOptions:\n" LONGOPTIONS "\n" DESCRIPTION "\n");
366 support ();
367 }
369 void
370 print_usage (void)
371 {
372 printf ("Usage:\n" " %s %s\n"
373 #ifdef HAVE_GETOPT_H
374 " %s (-h | --help) for detailed help\n"
375 " %s (-V | --version) for version information\n",
376 #else
377 " %s -h for detailed help\n"
378 " %s -V for version information\n",
379 #endif
380 progname, OPTIONS, progname, progname);
381 }