2 * collectd - src/vserver.c
3 * Copyright (C) 2006 Sebastian Harl
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Sebastian Harl <sh at tokkee.org>
32 #include <sys/types.h>
37 #define MODULE_NAME "vserver"
38 #define PROCDIR "/proc/virtual"
40 #if defined(KERNEL_LINUX)
41 # define VSERVER_HAVE_READ 1
43 # define VSERVER_HAVE_READ 0
44 #endif /* defined(KERNEL_LINUX) */
46 static char *rrd_unix = "vserver-%s/traffic-unix.rrd";
47 static char *rrd_inet = "vserver-%s/traffic-inet.rrd";
48 static char *rrd_inet6 = "vserver-%s/traffic-inet6.rrd";
49 static char *rrd_other = "vserver-%s/traffic-other.rrd";
50 static char *rrd_unspec = "vserver-%s/traffic-unspec.rrd";
52 static char *rrd_thread = "vserver-%s/vs_threads.rrd";
54 static char *rrd_load = "vserver-%s/load.rrd";
56 static char *rrd_procs = "vserver-%s/vs_processes.rrd";
57 static char *rrd_memory = "vserver-%s/vs_memory.rrd";
59 /* 9223372036854775807 == LLONG_MAX */
60 /* bytes transferred */
61 static char *ds_def_unix[] =
63 "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
64 "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
65 "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
68 static int ds_num_unix = 3;
70 static char *ds_def_inet[] =
72 "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
73 "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
74 "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
77 static int ds_num_inet = 3;
79 static char *ds_def_inet6[] =
81 "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
82 "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
83 "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
86 static int ds_num_inet6 = 3;
88 static char *ds_def_other[] =
90 "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
91 "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
92 "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
95 static int ds_num_other = 3;
97 static char *ds_def_unspec[] =
99 "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
100 "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
101 "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
104 static int ds_num_unspec = 3;
106 static char *ds_def_threads[] =
108 "DS:total:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
109 "DS:running:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
110 "DS:uninterruptible:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
111 "DS:onhold:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
114 static int ds_num_threads = 4;
116 static char *ds_def_load[] =
118 "DS:shortterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
119 "DS:midterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
120 "DS:longterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
123 static int ds_num_load = 3;
125 static char *ds_def_procs[] =
127 "DS:total:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
130 static int ds_num_procs = 1;
132 /* 9223372036854775807 == LLONG_MAX */
134 static char *ds_def_memory[] =
136 "DS:vm:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
137 "DS:vml:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
138 "DS:rss:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
139 "DS:anon:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
142 static int ds_num_memory = 4;
144 static int pagesize = 0;
146 static void vserver_init (void)
148 /* XXX Should we check for getpagesize () in configure?
149 * What's the right thing to do, if there is no getpagesize ()? */
150 pagesize = getpagesize ();
152 } /* static void vserver_init(void) */
154 static void vserver_unix_write (char *host, char *inst, char *val)
157 char filename[BUFSIZE];
159 len = snprintf (filename, BUFSIZE, rrd_unix, inst);
160 if ((len > 0) && (len < BUFSIZE))
161 rrd_update_file (host, filename, val, ds_def_unix, ds_num_unix);
163 } /* static void vserver_unix_write(char *host, char *inst, char *val) */
165 static void vserver_inet_write (char *host, char *inst, char *val)
168 char filename[BUFSIZE];
170 len = snprintf (filename, BUFSIZE, rrd_inet, inst);
171 if ((len > 0) && (len < BUFSIZE))
172 rrd_update_file (host, filename, val, ds_def_inet, ds_num_inet);
174 } /* static void vserver_inet_write(char *host, char *inst, char *val) */
176 static void vserver_inet6_write (char *host, char *inst, char *val)
179 char filename[BUFSIZE];
181 len = snprintf (filename, BUFSIZE, rrd_inet6, inst);
182 if ((len > 0) && (len < BUFSIZE))
183 rrd_update_file (host, filename, val, ds_def_inet6, ds_num_inet6);
185 } /* static void vserver_inet6_write(char *host, char *inst, char *val) */
187 static void vserver_other_write (char *host, char *inst, char *val)
190 char filename[BUFSIZE];
192 len = snprintf (filename, BUFSIZE, rrd_other, inst);
193 if ((len > 0) && (len < BUFSIZE))
194 rrd_update_file (host, filename, val, ds_def_other, ds_num_other);
196 } /* static void vserver_other_write(char *host, char *inst, char *val) */
198 static void vserver_unspec_write (char *host, char *inst, char *val)
201 char filename[BUFSIZE];
203 len = snprintf (filename, BUFSIZE, rrd_unspec, inst);
204 if ((len > 0) && (len < BUFSIZE))
205 rrd_update_file (host, filename, val, ds_def_unspec, ds_num_unspec);
207 } /* static void vserver_unspec_write(char *host, char *inst, char *val) */
209 static void vserver_threads_write (char *host, char *inst, char *val)
212 char filename[BUFSIZE];
214 len = snprintf (filename, BUFSIZE, rrd_thread, inst);
215 if ((len > 0) && (len < BUFSIZE))
216 rrd_update_file (host, filename, val, ds_def_threads, ds_num_threads);
218 } /* static void vserver_threads_write(char *host, char *inst, char *val) */
220 static void vserver_load_write (char *host, char *inst, char *val)
223 char filename[BUFSIZE];
225 len = snprintf (filename, BUFSIZE, rrd_load, inst);
226 if ((len > 0) && (len < BUFSIZE))
227 rrd_update_file (host, filename, val, ds_def_load, ds_num_load);
229 } /* static void vserver_load_write(char *host, char *inst, char *val) */
231 static void vserver_procs_write (char *host, char *inst, char *val)
234 char filename[BUFSIZE];
236 len = snprintf (filename, BUFSIZE, rrd_procs, inst);
237 if ((len > 0) && (len < BUFSIZE))
238 rrd_update_file (host, filename, val, ds_def_procs, ds_num_procs);
240 } /* static void vserver_procs_write(char *host, char *inst, char *val) */
242 static void vserver_memory_write (char *host, char *inst, char *val)
245 char filename[BUFSIZE];
247 len = snprintf (filename, BUFSIZE, rrd_memory, inst);
248 if ((len > 0) && (len < BUFSIZE))
249 rrd_update_file (host, filename, val, ds_def_memory, ds_num_memory);
251 } /* static void vserver_memory_write(char *host, char *inst, char *val) */
253 #if VSERVER_HAVE_READ
254 static void vserver_submit (char *inst, long long unix_in, long long unix_out,
255 long long unix_failed, long long inet_in, long long inet_out,
256 long long inet_failed, long long inet6_in, long long inet6_out,
257 long long inet6_failed, long long other_in, long long other_out,
258 long long other_failed, long long unspec_in, long long unspec_out,
259 long long unspec_failed, int t_total, int t_running,
260 int t_uninterruptible, int t_onhold, double avg1, double avg5,
261 double avg15, int p_total, long long vm, long long vml, long long rss,
265 char buffer[BUFSIZE];
267 len = snprintf (buffer, BUFSIZE,
268 "N:%lld:%lld:%lld", unix_in, unix_out, unix_failed);
270 if ((len > 0) && (len < BUFSIZE))
271 plugin_submit ("vserver_unix", inst, buffer);
274 len = snprintf (buffer, BUFSIZE,
275 "N:%lld:%lld:%lld", inet_in, inet_out, inet_failed);
277 if ((len > 0) && (len < BUFSIZE))
278 plugin_submit ("vserver_inet", inst, buffer);
281 len = snprintf (buffer, BUFSIZE,
282 "N:%lld:%lld:%lld", inet6_in, inet6_out, inet6_failed);
284 if ((len > 0) && (len < BUFSIZE))
285 plugin_submit ("vserver_inet6", inst, buffer);
288 len = snprintf (buffer, BUFSIZE,
289 "N:%lld:%lld:%lld", other_in, other_out, other_failed);
291 if ((len > 0) && (len < BUFSIZE))
292 plugin_submit ("vserver_other", inst, buffer);
295 len = snprintf (buffer, BUFSIZE,
296 "N:%lld:%lld:%lld", unspec_in, unspec_out, unspec_failed);
298 if ((len > 0) && (len < BUFSIZE))
299 plugin_submit ("vserver_unspec", inst, buffer);
302 len = snprintf (buffer, BUFSIZE, "N:%d:%d:%d:%d",
303 t_total, t_running, t_uninterruptible, t_onhold);
305 if ((len > 0) && (len < BUFSIZE))
306 plugin_submit ("vserver_threads", inst, buffer);
309 len = snprintf (buffer, BUFSIZE, "N:%.2f:%.2f:%.2f",
312 if ((len > 0) && (len < BUFSIZE))
313 plugin_submit ("vserver_load", inst, buffer);
316 len = snprintf (buffer, BUFSIZE, "N:%d",
319 if ((len > 0) && (len < BUFSIZE))
320 plugin_submit ("vserver_procs", inst, buffer);
323 len = snprintf (buffer, BUFSIZE, "N:%lld:%lld:%lld:%lld",
326 if ((len > 0) && (len < BUFSIZE))
327 plugin_submit ("vserver_memory", inst, buffer);
329 } /* static void vserver_submit() */
331 static inline long long __get_sock_bytes(const char *s)
341 static void vserver_read (void)
344 struct dirent *dent; /* 42 */
346 static complain_t complain_obj;
349 if (NULL == (proc = opendir (PROCDIR)))
351 plugin_complain (LOG_ERR, &complain_obj, "vserver plugin: "
352 "fopen (%s) failed: %s", PROCDIR, strerror (errno));
355 plugin_relief (LOG_NOTICE, &complain_obj, "vserver plugin: "
356 "fopen (%s) succeeded.", PROCDIR);
358 while (NULL != (dent = readdir (proc))) {
363 char buffer[BUFSIZE];
367 long long unix_s[3] = {-1, -1, -1};
368 long long inet[3] = {-1, -1, -1};
369 long long inet6[3] = {-1, -1, -1};
370 long long other[3] = {-1, -1, -1};
371 long long unspec[3] = {-1, -1, -1};
372 int threads[4] = {-1, -1, -1, -1};
373 double load[3] = {-1, -1, -1};
374 /* Just to be consistent ;-) */
376 long long memory[4] = {-1, -1, -1, -1};
378 if (dent->d_name[0] == '.')
381 /* XXX This check is just the result of a trial-and-error test.
382 * I did not find any documentation describing the d_type field. */
383 if (!(dent->d_type & 0x4))
384 /* This is not a directory */
387 /* socket message accounting */
388 len = snprintf (file, BUFSIZE, PROCDIR "/%s/cacct", dent->d_name);
389 if ((len < 0) || (len >= BUFSIZE))
392 if (NULL == (fh = fopen (file, "r"))) {
393 syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
397 while (NULL != fgets (buffer, BUFSIZE, fh)) {
398 if (strsplit (buffer, cols, 4) < 4)
401 if (0 == strcmp (cols[0], "UNIX:")) {
402 unix_s[0] = __get_sock_bytes (cols[1]);
403 unix_s[1] = __get_sock_bytes (cols[2]);
404 unix_s[2] = __get_sock_bytes (cols[3]);
406 else if (0 == strcmp (cols[0], "INET:")) {
407 inet[0] = __get_sock_bytes (cols[1]);
408 inet[1] = __get_sock_bytes (cols[2]);
409 inet[2] = __get_sock_bytes (cols[3]);
411 else if (0 == strcmp (cols[0], "INET6:")) {
412 inet6[0] = __get_sock_bytes (cols[1]);
413 inet6[1] = __get_sock_bytes (cols[2]);
414 inet6[2] = __get_sock_bytes (cols[3]);
416 else if (0 == strcmp (cols[0], "OTHER:")) {
417 other[0] = __get_sock_bytes (cols[1]);
418 other[1] = __get_sock_bytes (cols[2]);
419 other[2] = __get_sock_bytes (cols[3]);
421 else if (0 == strcmp (cols[0], "UNSPEC:")) {
422 unspec[0] = __get_sock_bytes (cols[1]);
423 unspec[1] = __get_sock_bytes (cols[2]);
424 unspec[2] = __get_sock_bytes (cols[3]);
430 /* thread information and load */
431 len = snprintf (file, BUFSIZE, PROCDIR "/%s/cvirt", dent->d_name);
432 if ((len < 0) || (len >= BUFSIZE))
435 if (NULL == (fh = fopen (file, "r"))) {
436 syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
440 while (NULL != fgets (buffer, BUFSIZE, fh)) {
441 int n = strsplit (buffer, cols, 4);
444 if (0 == strcmp (cols[0], "nr_threads:")) {
445 threads[0] = atoi (cols[1]);
447 else if (0 == strcmp (cols[0], "nr_running:")) {
448 threads[1] = atoi (cols[1]);
450 else if (0 == strcmp (cols[0], "nr_unintr:")) {
451 threads[2] = atoi (cols[1]);
453 else if (0 == strcmp (cols[0], "nr_onhold:")) {
454 threads[3] = atoi (cols[1]);
458 if (0 == strcmp (cols[0], "loadavg:")) {
459 load[0] = atof (cols[1]);
460 load[1] = atof (cols[2]);
461 load[2] = atof (cols[3]);
468 /* processes and memory usage */
469 len = snprintf (file, BUFSIZE, PROCDIR "/%s/limit", dent->d_name);
470 if ((len < 0) || (len >= BUFSIZE))
473 if (NULL == (fh = fopen (file, "r"))) {
474 syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
478 while (NULL != fgets (buffer, BUFSIZE, fh)) {
479 if (strsplit (buffer, cols, 2) < 2)
482 if (0 == strcmp (cols[0], "PROC:")) {
483 procs[0] = atoi (cols[1]);
485 else if (0 == strcmp (cols[0], "VM:")) {
486 memory[0] = atoll (cols[1]) * pagesize;
488 else if (0 == strcmp (cols[0], "VML:")) {
489 memory[1] = atoll (cols[1]) * pagesize;
491 else if (0 == strcmp (cols[0], "RSS:")) {
492 memory[2] = atoll (cols[1]) * pagesize;
494 else if (0 == strcmp (cols[0], "ANON:")) {
495 memory[3] = atoll (cols[1]) * pagesize;
501 /* XXX What to do in case of an error (i.e. some value is
504 vserver_submit (dent->d_name, unix_s[0], unix_s[1], unix_s[2],
505 inet[0], inet[1], inet[2], inet6[0], inet6[1], inet6[2],
506 other[0], other[1], other[2], unspec[0], unspec[1], unspec[2],
507 threads[0], threads[1], threads[2], threads[3], load[0],
508 load[1], load[2], procs[0], memory[0], memory[1], memory[2],
514 } /* static void vserver_read(void) */
516 # define vserver_read NULL
517 #endif /* VSERVER_HAVE_READ */
519 void module_register (void)
521 plugin_register (MODULE_NAME, vserver_init, vserver_read, NULL);
522 plugin_register ("vserver_unix", NULL, NULL, vserver_unix_write);
523 plugin_register ("vserver_inet", NULL, NULL, vserver_inet_write);
524 plugin_register ("vserver_inet6", NULL, NULL, vserver_inet6_write);
525 plugin_register ("vserver_other", NULL, NULL, vserver_other_write);
526 plugin_register ("vserver_unspec", NULL, NULL, vserver_unspec_write);
527 plugin_register ("vserver_threads", NULL, NULL, vserver_threads_write);
528 plugin_register ("vserver_load", NULL, NULL, vserver_load_write);
529 plugin_register ("vserver_procs", NULL, NULL, vserver_procs_write);
530 plugin_register ("vserver_memory", NULL, NULL, vserver_memory_write);
532 } /* void module_register(void) */
534 /* vim: set ts=4 sw=4 noexpandtab : */