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 int option_index = 0;
218 static struct option long_options[] = {
219 {"logfile", required_argument, 0, 'F'},
220 {"expires", required_argument, 0, 'e'},
221 {"aggregation", required_argument, 0, 'a'},
222 {"variable", required_argument, 0, 'v'},
223 {"critical", required_argument, 0, 'c'},
224 {"warning", required_argument, 0, 'w'},
225 {"label", required_argument, 0, 'l'},
226 {"units", required_argument, 0, 'u'},
227 {"verbose", no_argument, 0, 'v'},
228 {"version", no_argument, 0, 'V'},
229 {"help", no_argument, 0, 'h'},
230 {0, 0, 0, 0}
231 };
233 if (argc < 2)
234 return ERROR;
236 for (c = 1; c < argc; c++) {
237 if (strcmp ("-to", argv[c]) == 0)
238 strcpy (argv[c], "-t");
239 else if (strcmp ("-wt", argv[c]) == 0)
240 strcpy (argv[c], "-w");
241 else if (strcmp ("-ct", argv[c]) == 0)
242 strcpy (argv[c], "-c");
243 }
245 while (1) {
246 c = getopt_long (argc, argv, "hVF:e:a:v:c:w:l:u:", long_options,
247 &option_index);
249 if (c == -1 || c == EOF)
250 break;
252 switch (c) {
253 case 'F': /* input file */
254 log_file = optarg;
255 break;
256 case 'e': /* ups name */
257 expire_minutes = atoi (optarg);
258 break;
259 case 'a': /* port */
260 if (!strcmp (optarg, "MAX"))
261 use_average = FALSE;
262 else
263 use_average = TRUE;
264 break;
265 case 'v':
266 variable_number = atoi (optarg);
267 if (variable_number < 1 || variable_number > 2)
268 usage ("Invalid variable number\n");
269 break;
270 case 'w': /* critical time threshold */
271 value_warning_threshold = strtoul (optarg, NULL, 10);
272 break;
273 case 'c': /* warning time threshold */
274 value_critical_threshold = strtoul (optarg, NULL, 10);
275 break;
276 case 'l': /* label */
277 value_label = optarg;
278 break;
279 case 'u': /* timeout */
280 units_label = optarg;
281 break;
282 case 'V': /* version */
283 print_revision (progname, REVISION);
284 exit (STATE_OK);
285 case 'h': /* help */
286 print_help ();
287 exit (STATE_OK);
288 case '?': /* help */
289 usage ("Invalid argument\n");
290 }
291 }
293 c = optind;
294 if (log_file == NULL && argc > c) {
295 log_file = argv[c++];
296 }
298 if (expire_minutes <= 0 && argc > c) {
299 if (is_intpos (argv[c]))
300 expire_minutes = atoi (argv[c++]);
301 else
302 terminate (STATE_UNKNOWN,
303 "%s is not a valid expiration time\nUse '%s -h' for additional help\n",
304 argv[c], progname);
305 }
307 if (argc > c && strcmp (argv[c], "MAX") == 0) {
308 use_average = FALSE;
309 c++;
310 }
311 else if (argc > c && strcmp (argv[c], "AVG") == 0) {
312 use_average = TRUE;
313 c++;
314 }
316 if (argc > c && variable_number == -1) {
317 variable_number = atoi (argv[c++]);
318 if (variable_number < 1 || variable_number > 2) {
319 printf ("%s :", argv[c]);
320 usage ("Invalid variable number\n");
321 }
322 }
324 if (argc > c && value_warning_threshold == 0) {
325 value_warning_threshold = strtoul (argv[c++], NULL, 10);
326 }
328 if (argc > c && value_critical_threshold == 0) {
329 value_critical_threshold = strtoul (argv[c++], NULL, 10);
330 }
332 if (argc > c && strlen (value_label) == 0) {
333 value_label = argv[c++];
334 }
336 if (argc > c && strlen (units_label) == 0) {
337 units_label = argv[c++];
338 }
340 return validate_arguments ();
341 }
343 int
344 validate_arguments (void)
345 {
346 if (variable_number == -1)
347 usage ("You must supply the variable number\n");
349 return OK;
350 }
352 void
353 print_help (void)
354 {
355 print_revision (progname, REVISION);
356 printf ("%s\n\n%s\n", COPYRIGHT, SUMMARY);
357 print_usage ();
358 printf ("\nOptions:\n" LONGOPTIONS "\n" DESCRIPTION "\n");
359 support ();
360 }
362 void
363 print_usage (void)
364 {
365 printf ("Usage:\n" " %s %s\n"
366 " %s (-h | --help) for detailed help\n"
367 " %s (-V | --version) for version information\n",
368 progname, OPTIONS, progname, progname);
369 }