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