1 /*----------------------------------------------------------------------------*/
2 /* Xymon RRD handler module.                                                  */
3 /*                                                                            */
4 /* Copyright (C) 2004-2011 Henrik Storner <henrik@hswn.dk>                    */
5 /*                                                                            */
6 /* This program is released under the GNU General Public License (GPL),       */
7 /* version 2. See the file "COPYING" for details.                             */
8 /*                                                                            */
9 /*----------------------------------------------------------------------------*/
10 
11 static char la_rcsid[] = "$Id: do_la.c 7677 2015-10-01 14:09:57Z jccleaver $";
12 
do_la_rrd(char * hostname,char * testname,char * classname,char * pagepaths,char * msg,time_t tstamp)13 int do_la_rrd(char *hostname, char *testname, char *classname, char *pagepaths, char *msg, time_t tstamp)
14 {
15 	static char *la_params[]          = { "DS:la:GAUGE:600:U:U", NULL };
16 	static void *la_tpl               = NULL;
17 	static char *clock_params[]       = { "DS:la:GAUGE:600:U:U", NULL }; /* "la" is a misnomer, but to stay compatiable with existing RRD files */
18 	static void *clock_tpl            = NULL;
19 
20 	static pcre *as400_exp = NULL;
21 	static pcre *zVM_exp = NULL;
22 	static time_t starttime = 0;
23 
24 	char *p, *eoln = NULL;
25 	int gotusers=0, gotprocs=0, gotload=0, gotclock=0;
26 	int users=0, procs=0, load=0, clockdiff=0;
27 	time_t now = getcurrenttime(NULL);
28 
29 	if (la_tpl == NULL) la_tpl = setup_template(la_params);
30 	if (clock_tpl == NULL) clock_tpl = setup_template(clock_params);
31 	if (starttime == 0) starttime = now;
32 
33 	if (strstr(msg, "bb-xsnmp")) {
34 		/*
35 		 * bb-xsnmp.pl script output.
36 		 *
37 		 * green Tue Apr  5 12:57:37 2005 up: 254.58 days, CPU Usage=  9%
38 		 *
39 		 * &green  CPU Time in Busy Mode:   9%
40 		 * &green  CPU Time in Idle Mode:  91%
41 		 *
42 		 * &yellow CPU Usage Threshold: 90%
43 		 * &red CPU Usage Threshold: 95%
44 		 *
45 		 * <!-- Enterprise: netapp , Version: 6.42 -->
46 		 * bb-xsnmp.pl Version: 1.78
47 		 */
48 
49 		p = strstr(msg, "CPU Usage=");
50 		if (p) {
51 			p += strlen("CPU Usage=");
52 			gotload = 1;
53 			load = atoi(p);
54 		}
55 
56 		goto done_parsing;
57 	}
58 	else if (strstr(msg, "z/VM") || strstr(msg, "VSE/ESA") || strstr(msg, "z/VSE") || strstr(msg, "z/OS")) {
59 		/* z/VM cpu message. Looks like this, from Rich Smrcina (client config mode):
60 		 * green 5 Apr 2005 20:07:34  CPU Utilization  7% z/VM Version 4 Release 4.0, service level 0402 (32-bit) AVGPROC-007% 01
61 		 * VSE/ESA or z/VSE cpu message.
62 		 * VSE/ESA 2.7.2 cr IPLed on ...
63 		 * or
64 		 * z/VSE 3.1.1 cr IPLed on ...
65 		 * In server (centralized) config mode or for z/OS (which is centralized config only)
66 		 * the operating system name is part of the message (as in the tests above).
67 		 */
68 
69 		int ovector[30];
70 		char w[100];
71 		int res;
72 
73 		if (zVM_exp == NULL) {
74 			const char *errmsg = NULL;
75 			int errofs = 0;
76 
77 			zVM_exp = pcre_compile(".* CPU Utilization *([0-9]+)%", PCRE_CASELESS, &errmsg, &errofs, NULL);
78 		}
79 
80 		res = pcre_exec(zVM_exp, NULL, msg, strlen(msg), 0, 0, ovector, (sizeof(ovector)/sizeof(int)));
81 		if (res >= 0) {
82 			/* We have a match - pick up the data. */
83 			*w = '\0'; if (res > 0) pcre_copy_substring(msg, ovector, res, 1, w, sizeof(w));
84 			if (strlen(w)) {
85 				load = atoi(w); gotload = 1;
86 			}
87 		}
88 
89 		goto done_parsing;
90 	}
91 
92 	eoln = strchr(msg, '\n'); if (eoln) *eoln = '\0';
93 	p = strstr(msg, "up: ");
94 	if (!p) p = strstr(msg, "Uptime:");	/* Netapp filerstats2bb script */
95 	if (!p) p = strstr(msg, "uptime:");
96 	if (p) {
97 		/* First line of cpu report, contains "up: 159 days, 1 users, 169 procs, load=21" */
98 		p = strchr(p, ',');
99 		if (p) {
100 			gotusers = (sscanf(p, ", %d users", &users) == 1);
101 			p = strchr(p+1, ',');
102 		}
103 
104 		if (p) {
105 			gotprocs = (sscanf(p, ", %d procs", &procs) == 1);
106 			p = strchr(p+1, ',');
107 		}
108 
109 		/*
110 		 * Load can be either
111 		 * -  "load=xx%"   (Windows)
112 		 * -  "load=xx.xx" (Unix, DISPREALLOADAVG=TRUE)
113 		 * -  "load=xx"    (Unix, DISPREALLOADAVG=FALSE)
114 		 *
115 		 * We want the load in percent (Windows), or LA*100 (Unix).
116 		 */
117 		p = strstr(msg, "load=");
118 		if (p) {
119 			p += 5;
120 			if (strchr(p, '%')) {
121 				gotload = 1;
122 				load = atoi(p);
123 			}
124 			else if (strchr(p, '.')) {
125 				gotload = 1;
126 				load = 100*atoi(p);
127 				/* Find the decimal part, and cut off at 2 decimals */
128 				p = strchr(p, '.'); if (strlen(p) > 3) *(p+3) = '\0';
129 				load += atoi(p+1);
130 			}
131 			else {
132 				gotload = 1;
133 				load = atoi(p);
134 			}
135 		}
136 	}
137 	else {
138 		/*
139 		 * No "uptime" in message - could be from an AS/400. They look like this:
140 		 * green March 21, 2005 12:33:24 PM EST deltacdc 108 users 45525 jobs(126 batch,0 waiting for message), load=26%
141 		 */
142 		int ovector[30];
143 		char w[100];
144 		int res;
145 
146 		if (as400_exp == NULL) {
147 			const char *errmsg = NULL;
148 			int errofs = 0;
149 
150 			as400_exp = pcre_compile(".* ([0-9]+) users ([0-9]+) jobs.* load=([0-9]+)\\%",
151 						 PCRE_CASELESS, &errmsg, &errofs, NULL);
152 		}
153 
154 		res = pcre_exec(as400_exp, NULL, msg, strlen(msg), 0, 0, ovector, (sizeof(ovector)/sizeof(int)));
155 		if (res >= 0) {
156 			/* We have a match - pick up the AS/400 data. */
157 			*w = '\0'; if (res > 0) pcre_copy_substring(msg, ovector, res, 1, w, sizeof(w));
158 			if (strlen(w)) {
159 				users = atoi(w); gotusers = 1;
160 			}
161 
162 			*w = '\0'; if (res > 0) pcre_copy_substring(msg, ovector, res, 3, w, sizeof(w));
163 			if (strlen(w)) {
164 				load = atoi(w); gotload = 1;
165 			}
166 		}
167 	}
168 
169 done_parsing:
170 	if (eoln) *eoln = '\n';
171 
172 	p = strstr(msg, "System clock is ");
173 	if (p) {
174 		if (sscanf(p, "System clock is %d seconds off", &clockdiff) == 1) gotclock = 1;
175 	}
176 
177 	if (!gotload) {
178 		/* See if it's a report from the ciscocpu.pl script. */
179 		p = strstr(msg, "<br>CPU 5 min average:");
180 		if (p) {
181 			/* It reports in % cpu utilization */
182 			p = strchr(p, ':');
183 			load = atoi(p+1);
184 			gotload = 1;
185 		}
186 	}
187 
188 	if (gotload) {
189 		setupfn("%s.rrd", "la");
190 		snprintf(rrdvalues, sizeof(rrdvalues), "%d:%d", (int)tstamp, load);
191 		create_and_update_rrd(hostname, testname, classname, pagepaths, la_params, la_tpl);
192 	}
193 
194 	if (gotprocs) {
195 		setupfn("%s.rrd", "procs");
196 		snprintf(rrdvalues, sizeof(rrdvalues), "%d:%d", (int)tstamp, procs);
197 		create_and_update_rrd(hostname, testname, classname, pagepaths, la_params, la_tpl);
198 	}
199 
200 	if (gotusers) {
201 		setupfn("%s.rrd", "users");
202 		snprintf(rrdvalues, sizeof(rrdvalues), "%d:%d", (int)tstamp, users);
203 		create_and_update_rrd(hostname, testname, classname, pagepaths, la_params, la_tpl);
204 	}
205 
206 	if (gotclock) {
207 		setupfn("%s.rrd", "clock");
208 		snprintf(rrdvalues, sizeof(rrdvalues), "%d:%d", (int)tstamp, clockdiff);
209 		create_and_update_rrd(hostname, testname, classname, pagepaths, clock_params, clock_tpl);
210 	}
211 
212 	/*
213 	 * If we have run for less than 6 minutes, drop the memory updates here.
214 	 * We want to be sure not to use memory statistics from the CPU report
215 	 * if there is a memory add-on sending a separate memory statistics
216 	 */
217 	if ((now - starttime) < 360) return 0;
218 
219 	if (!memhosts_init || (xtreeFind(memhosts, hostname) == xtreeEnd(memhosts))) {
220 		/* Pick up memory statistics */
221 		int found, overflow, realuse, swapuse;
222 		long long phystotal, physavail, pagetotal, pageavail;
223 
224 		found = overflow = realuse = swapuse = 0;
225 		phystotal = physavail = pagetotal = pageavail = 0;
226 
227 		p = strstr(msg, "Total Physical memory:");
228 		if (p) {
229 			phystotal = str2ll(strchr(p, ':') + 1, NULL);
230 			if (phystotal != LONG_MAX) found++; else overflow++;
231 		}
232 
233 		if (found == 1) {
234 			p = strstr(msg, "Available Physical memory:");
235 			if (p) {
236 				physavail = str2ll(strchr(p, ':') + 1, NULL);
237 				if (physavail != LONG_MAX) found++; else overflow++;
238 			}
239 		}
240 
241 		if (found == 2) {
242 			p = strstr(msg, "Total PageFile size:");
243 			if (p) {
244 				pagetotal = str2ll(strchr(p, ':') + 1, NULL);
245 				if (pagetotal != LONG_MAX) found++; else overflow++;
246 			}
247 		}
248 
249 		if (found == 3) {
250 			p = strstr(msg, "Available PageFile size:");
251 			if (p) {
252 				pageavail = str2ll(strchr(p, ':') + 1, NULL);
253 				if (pageavail != LONG_MAX) found++; else overflow++;
254 			}
255 		}
256 
257 		if (found == 4) {
258 			if (!phystotal || !pagetotal) { errprintf("Host %s cpu report had 0 total physical/pagefile memory listed\n", hostname); return 0; }
259 			phystotal = phystotal / 100;
260 			pagetotal = pagetotal / 100;
261 			realuse = 100 - (physavail / phystotal);
262 			swapuse = 100 - (pageavail / pagetotal);
263 			do_memory_rrd_update(tstamp, hostname, testname, classname, pagepaths, realuse, swapuse, -1);
264 		}
265 		else if (overflow) {
266 			errprintf("Host %s cpu report overflows in memory usage calculation\n", hostname);
267 		}
268 	}
269 
270 	return 0;
271 }
272 
273