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