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 iostat_rcsid[] = "$Id: do_iostat.c 7058 2012-07-14 15:01:11Z storner $";
12 
13 static char *iostat_params[] = { "DS:rs:GAUGE:600:1:U", "DS:ws:GAUGE:600:1:U",
14 				"DS:krs:GAUGE:600:1:U", "DS:kws:GAUGE:600:1:U",
15 				"DS:wait:GAUGE:600:1:U", "DS:actv:GAUGE:600:1:U",
16 				"DS:wsvc_t:GAUGE:600:1:U", "DS:asvc_t:GAUGE:600:1:U",
17 				"DS:w:GAUGE:600:1:U", "DS:b:GAUGE:600:1:U",
18 				"DS:sw:GAUGE:600:1:U", "DS:hw:GAUGE:600:1:U",
19 				"DS:trn:GAUGE:600:1:U", "DS:tot:GAUGE:600:1:U",
20 				NULL };
21 static void *iostat_tpl      = NULL;
22 
23 
do_iostatdisk_rrd(char * hostname,char * testname,char * classname,char * pagepaths,char * msg,time_t tstamp)24 int do_iostatdisk_rrd(char *hostname, char *testname, char *classname, char *pagepaths, char *msg, time_t tstamp)
25 {
26 	char *dataline;
27 
28 	/*
29 	 * This format is reported in the "iostatdisk" section:
30 	 *
31 	 * data HOSTNAME.iostatdisk
32 	 * solaris
33 	 * extended device statistics
34 	 * device,r/s,w/s,kr/s,kw/s,wait,actv,svc_t,%w,%b,
35 	 * dad0,a,0.0,0.7,0.0,5.8,0.0,0.0,4.3,0,0
36 	 * dad0,b,0.0,0.0,0.0,0.0,0.0,0.0,27.9,0,0
37 	 * dad0,c,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
38 	 * dad0,e,0.0,0.6,0.0,4.1,0.0,0.0,3.7,0,0
39 	 * dad0,f,0.0,17.2,0.0,89.7,0.0,0.0,0.2,0,0
40 	 * dad0,h,0.0,0.5,0.0,2.7,0.0,0.0,2.2,0,0
41 	 * dad1,c,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
42 	 * dad1,h,0.0,0.0,0.0,0.0,0.0,0.0,27.1,0,0
43 	 * nfs1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
44 	 * extended device statistics
45 	 * device,r/s,w/s,kr/s,kw/s,wait,actv,svc_t,%w,%b,
46 	 * dad0,a,0.0,0.6,0.0,5.1,0.0,0.0,4.2,0,0
47 	 * dad0,b,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
48 	 * dad0,c,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
49 	 * dad0,e,0.0,0.5,0.0,3.4,0.0,0.0,3.2,0,0
50 	 * dad0,f,0.0,12.6,0.0,65.6,0.0,0.0,0.2,0,0
51 	 * dad0,h,0.0,0.4,0.0,2.4,0.0,0.0,1.8,0,0
52 	 * dad1,c,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
53 	 * dad1,h,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
54 	 * nfs1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0,0
55 	 *
56 	 * There are two chunks of data: Like vmstat, we first get a
57 	 * summary at the start of data collection, and then another
58 	 * with the 5-minute average. So we must skip the first chunk.
59 	 *
60 	 * Note that real disks are identified by "dad0,a" whereas
61 	 * NFS mounts show up as "nfs1" (no comma!).
62 	 */
63 
64 	if (iostat_tpl == NULL) iostat_tpl = setup_template(iostat_params);
65 
66 	dataline = strstr(msg, "\ndevice,r/s,w/s,kr/s,kw/s,wait,actv,svc_t,%w,%b,");
67 	if (!dataline) return -1;
68 	dataline = strstr(dataline+1, "\ndevice,r/s,w/s,kr/s,kw/s,wait,actv,svc_t,%w,%b,");
69 	if (!dataline) return -1;
70 
71 	dataline++;
72 	while (dataline && *dataline) {
73 		char *elems[12];
74 		char *eoln, *p, *id = "";
75 		int i, valofs;
76 
77 		eoln = strchr(dataline, '\n'); if (eoln) *eoln = '\0';
78 
79 		memset(elems, 0, sizeof(elems));
80 		p = elems[0] = dataline; i=0;
81 		do {
82 			p = strchr(p+1, ',');
83 			i++;
84 			if (p) {
85 				*p = '\0';
86 				elems[i] = p+1;
87 			}
88 		} while (p);
89 
90 		if (elems[9] == NULL) goto nextline;
91 		else if (elems[10] == NULL) {
92 			/* NFS "disk" */
93 			id = elems[0];
94 			valofs = 1;
95 		}
96 		else {
97 			/* Normal disk - re-instate the "," between elems[0] and elems[1] */
98 			*(elems[1]-1) = ','; /* Hack! */
99 			valofs = 2;
100 		}
101 
102 		setupfn2("%s.%s.rrd", "iostat", id);
103 		snprintf(rrdvalues, sizeof(rrdvalues), "%d:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s",
104 			(int) tstamp,
105 			elems[valofs],		/* r/s */
106 			elems[valofs+1],	/* w/s */
107 			elems[valofs+2],	/* kr/s */
108 			elems[valofs+3],	/* kw/s */
109 			elems[valofs+4],	/* wait */
110 			elems[valofs+5],	/* actv */
111 			elems[valofs+6],	/* wsvc_t - we use svc_t here */
112 			"U",			/* asvc_t not in this format */
113 			elems[valofs+7],	/* %w */
114 			elems[valofs+8],	/* %b */
115 			"U", "U", "U", "U"	/* sw, hw, trn, tot not in this format */
116 		       );
117 
118 nextline:
119 		dataline = (eoln ? eoln+1 : NULL);
120 	}
121 
122 	return 0;
123 }
124 
do_iostat_rrd(char * hostname,char * testname,char * classname,char * pagepaths,char * msg,time_t tstamp)125 int do_iostat_rrd(char *hostname, char *testname, char *classname, char *pagepaths, char *msg, time_t tstamp)
126 {
127 	/*
128 	 * BEGINKEY
129 	 * d0 /
130 	 * d5 /var
131 	 * d6 /export
132 	 * ENDKEY
133 	 * BEGINDATA
134 	 *     r/s    w/s   kr/s   kw/s wait actv wsvc_t asvc_t  %w  %b s/w h/w trn tot device
135 	 *     0.9    2.8    7.3    1.8  0.0  0.0    2.7    9.3   1   2   0   0   0   0 d0
136 	 *     0.1    0.3    0.8    0.5  0.0  0.0    5.2   11.0   0   0   0   0   0   0 d5
137 	 *     0.1    0.2    1.0    1.1  0.0  0.0    6.9   12.9   0   0   0   0   0   0 d6
138 	 * ENDDATA
139 	 */
140 
141 	typedef struct iostatkey_t {
142 		char *key;
143 		char *value;
144 		struct iostatkey_t *next;
145 	} iostatkey_t;
146 
147 	enum { S_NONE, S_KEYS, S_DATA } state;
148 	iostatkey_t *keyhead = NULL;
149 	iostatkey_t *newkey;
150 	char *eoln, *curline;
151 	char *buf, *p;
152 	float v[14];
153 	char marker[MAX_LINE_LEN];
154 
155 	MEMDEFINE(marker);
156 
157 	if (iostat_tpl == NULL) iostat_tpl = setup_template(iostat_params);
158 
159 	curline = msg; state = S_NONE;
160 	while (curline) {
161 		eoln = strchr(curline, '\n'); if (eoln) *eoln = '\0';
162 
163 		if (strncmp(curline, "BEGINKEY", 8) == 0) { state = S_KEYS; }
164 		else if (strncmp(curline, "ENDKEY", 6) == 0) { state = S_NONE; }
165 		else if (strncmp(curline, "BEGINDATA", 9) == 0) { state = S_DATA; }
166 		else if (strncmp(curline, "ENDDATA", 7) == 0) { state = S_NONE; }
167 		else {
168 			switch (state) {
169 			  case S_NONE:
170 				break;
171 
172 			  case S_KEYS:
173 				buf = xstrdup(curline);
174 				newkey = (iostatkey_t *)xcalloc(1, sizeof(iostatkey_t));
175 
176 				p = strtok(buf, " ");
177 				if (p) newkey->key = xstrdup(p);
178 
179 				p = strtok(NULL, " ");
180 				if (p) {
181 					if (strcmp(p, "/") == 0) newkey->value = xstrdup(",root");
182 					else {
183 						newkey->value = xstrdup(p);
184 						p = newkey->value; while ((p = strchr(p, '/')) != NULL) *p = ',';
185 					}
186 				}
187 				xfree(buf);
188 
189 				if (newkey->key && newkey->value) {
190 					newkey->next = keyhead; keyhead = newkey;
191 				}
192 				else {
193 					if (newkey->key) xfree(newkey->key);
194 					if (newkey->value) xfree(newkey->value);
195 					xfree(newkey);
196 				}
197 				break;
198 
199 			  case S_DATA:
200 				buf = xstrdup(curline);
201 				if (sscanf(buf, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %s",
202 					   &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6],
203 					   &v[7], &v[8], &v[9], &v[10], &v[11], &v[12], &v[13], marker) == 15) {
204 
205 					/* Find the disk name */
206 					for (newkey = keyhead; (newkey && strcmp(newkey->key, marker)); newkey = newkey->next) ;
207 
208 					if (newkey) {
209 						setupfn2("%s.%s.rrd", "iostat", newkey->value);
210 						snprintf(rrdvalues, sizeof(rrdvalues), "%d:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f",
211 							(int) tstamp,
212 							v[0], v[1], v[2], v[3], v[4], v[5], v[6],
213 							v[7], v[8], v[9], v[10], v[11], v[12], v[13]);
214 						create_and_update_rrd(hostname, testname, classname, pagepaths, iostat_params, iostat_tpl);
215 					}
216 				}
217 				xfree(buf);
218 				break;
219 			}
220 		}
221 
222 		if (eoln) { *eoln = '\n'; curline = eoln + 1; }
223 		else { curline = NULL; }
224 	}
225 
226 	/* Free the keylist */
227 	while (keyhead) {
228 		newkey = keyhead;
229 		keyhead = keyhead->next;
230 		if (newkey->key) xfree(newkey->key);
231 		if (newkey->value) xfree(newkey->value);
232 		xfree(newkey);
233 	}
234 
235 	MEMUNDEFINE(marker);
236 
237 	return 0;
238 }
239 
240