Code

00a1e6ad49ca671839e1823bd42d3200e700c493
[collectd.git] / src / vserver.c
1 /**
2  * collectd - src/vserver.c
3  * Copyright (C) 2006,2007  Sebastian Harl
4  *
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.
9  *
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.
14  *
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
18  *
19  * Authors:
20  *   Sebastian Harl <sh at tokkee.org>
21  **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #include <dirent.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <sys/types.h>
33 #include <unistd.h>
35 #define BUFSIZE 512
37 #define MODULE_NAME "vserver"
38 #define PROCDIR "/proc/virtual"
40 #if defined(KERNEL_LINUX)
41 # define VSERVER_HAVE_READ 1
42 #else
43 # define VSERVER_HAVE_READ 0
44 #endif /* defined(KERNEL_LINUX) */
46 static data_source_t octets_dsrc[2] =
47 {
48         {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
49         {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
50 };
52 static data_set_t octets_ds =
53 {
54         "if_octets", 2, octets_dsrc
55 };
57 static data_source_t load_dsrc[3] =
58 {
59         {"shortterm", DS_TYPE_GAUGE, 0.0, 100.0},
60         {"midterm",   DS_TYPE_GAUGE, 0.0, 100.0},
61         {"longterm",  DS_TYPE_GAUGE, 0.0, 100.0}
62 };
64 static data_set_t load_ds =
65 {
66         "load", 3, load_dsrc
67 };
69 static data_source_t threads_dsrc[1] =
70 {
71         {"value", DS_TYPE_GAUGE, 0.0, 65535.0}
72 };
74 static data_set_t threads_ds =
75 {
76         "vs_threads", 1, threads_dsrc
77 };
79 static data_source_t processes_dsrc[1] =
80 {
81         {"value", DS_TYPE_GAUGE, 0.0, 65535.0}
82 };
84 static data_set_t processes_ds =
85 {
86         "vs_processes", 1, processes_dsrc
87 };
89 static data_source_t memory_dsrc[1] =
90 {
91         {"value", DS_TYPE_GAUGE, 0.0, 9223372036854775807.0}
92 };
94 static data_set_t memory_ds =
95 {
96         "vs_memory", 1, memory_dsrc
97 };
99 #if VSERVER_HAVE_READ
100 static int pagesize = 0;
102 static int vserver_init (void)
104         /* XXX Should we check for getpagesize () in configure?
105          * What's the right thing to do, if there is no getpagesize ()? */
106         pagesize = getpagesize ();
108         return (0);
109 } /* static void vserver_init(void) */
111 static void traffic_submit (const char *plugin_instance,
112                 const char *type_instance, counter_t rx, counter_t tx)
114         value_t values[2];
115         value_list_t vl = VALUE_LIST_INIT;
117         values[0].counter = rx;
118         values[1].counter = tx;
120         vl.values = values;
121         vl.values_len = STATIC_ARRAY_SIZE (values);
122         vl.time = time (NULL);
123         strcpy (vl.host, hostname_g);
124         strcpy (vl.plugin, "vserver");
125         strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
126         strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
128         plugin_dispatch_values ("if_octets", &vl);
129 } /* void traffic_submit */
131 static void load_submit (const char *plugin_instance,
132                 gauge_t snum, gauge_t mnum, gauge_t lnum)
134         value_t values[3];
135         value_list_t vl = VALUE_LIST_INIT;
137         values[0].gauge = snum;
138         values[1].gauge = mnum;
139         values[2].gauge = lnum;
141         vl.values = values;
142         vl.values_len = STATIC_ARRAY_SIZE (values);
143         vl.time = time (NULL);
144         strcpy (vl.host, hostname_g);
145         strcpy (vl.plugin, "vserver");
146         strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
148         plugin_dispatch_values ("load", &vl);
151 static void submit_gauge (const char *plugin_instance, const char *type,
152                 const char *type_instance, gauge_t value)
155         value_t values[1];
156         value_list_t vl = VALUE_LIST_INIT;
158         values[0].gauge = value;
160         vl.values = values;
161         vl.values_len = STATIC_ARRAY_SIZE (values);
162         vl.time = time (NULL);
163         strcpy (vl.host, hostname_g);
164         strcpy (vl.plugin, "vserver");
165         strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
166         strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
168         plugin_dispatch_values (type, &vl);
169 } /* void submit_gauge */
171 static inline long long __get_sock_bytes(const char *s)
173         while (s[0] != '/')
174                 ++s;
176         /* Remove '/' */
177         ++s;
178         return atoll(s);
181 static int vserver_read (void)
183         DIR                     *proc;
184         struct dirent   *dent; /* 42 */
186         static complain_t complain_obj;
188         errno = 0;
189         if (NULL == (proc = opendir (PROCDIR)))
190         {
191                 plugin_complain (LOG_ERR, &complain_obj, "vserver plugin: "
192                                 "fopen (%s) failed: %s", PROCDIR, strerror (errno));
193                 return (-1);
194         }
195         plugin_relief (LOG_NOTICE, &complain_obj, "vserver plugin: "
196                         "fopen (%s) succeeded.", PROCDIR);
198         while (NULL != (dent = readdir (proc)))
199         {
200                 int  len;
201                 char file[BUFSIZE];
203                 FILE *fh;
204                 char buffer[BUFSIZE];
206                 char *cols[4];
208                 if (dent->d_name[0] == '.')
209                         continue;
211                 /* This is not a directory */
212                 if (dent->d_type != DT_DIR)
213                         continue;
215                 /* socket message accounting */
216                 len = snprintf (file, BUFSIZE, PROCDIR "/%s/cacct", dent->d_name);
217                 if ((len < 0) || (len >= BUFSIZE))
218                         continue;
220                 if (NULL == (fh = fopen (file, "r")))
221                         syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
223                 while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
224                 {
225                         counter_t rx;
226                         counter_t tx;
227                         char *type_instance;
229                         if (strsplit (buffer, cols, 4) < 4)
230                                 continue;
232                         if (0 == strcmp (cols[0], "UNIX:"))
233                                 type_instance = "unix";
234                         else if (0 == strcmp (cols[0], "INET:"))
235                                 type_instance = "inet";
236                         else if (0 == strcmp (cols[0], "INET6:"))
237                                 type_instance = "inet6";
238                         else if (0 == strcmp (cols[0], "OTHER:"))
239                                 type_instance = "other";
240                         else if (0 == strcmp (cols[0], "UNSPEC:"))
241                                 type_instance = "unspec";
242                         else
243                                 continue;
245                         rx = __get_sock_bytes (cols[1]);
246                         tx = __get_sock_bytes (cols[2]);
247                         /* cols[3] == errors */
249                         traffic_submit (dent->d_name, type_instance, rx, tx);
250                 } /* while (fgets) */
252                 if (fh != NULL)
253                 {
254                         fclose (fh);
255                         fh = NULL;
256                 }
258                 /* thread information and load */
259                 len = snprintf (file, BUFSIZE, PROCDIR "/%s/cvirt", dent->d_name);
260                 if ((len < 0) || (len >= BUFSIZE))
261                         continue;
263                 if (NULL == (fh = fopen (file, "r")))
264                         syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
266                 while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
267                 {
268                         int n = strsplit (buffer, cols, 4);
270                         if (2 == n)
271                         {
272                                 char   *type_instance;
273                                 gauge_t value;
275                                 if (0 == strcmp (cols[0], "nr_threads:"))
276                                         type_instance = "total";
277                                 else if (0 == strcmp (cols[0], "nr_running:"))
278                                         type_instance = "running";
279                                 else if (0 == strcmp (cols[0], "nr_unintr:"))
280                                         type_instance = "uninterruptable";
281                                 else if (0 == strcmp (cols[0], "nr_onhold:"))
282                                         type_instance = "onhold";
283                                 else
284                                         continue;
286                                 value = atof (cols[1]);
287                                 submit_gauge (dent->d_name, "vs_threads", type_instance, value);
288                         }
289                         else if (4 == n) {
290                                 if (0 == strcmp (cols[0], "loadavg:"))
291                                 {
292                                         gauge_t snum = atof (cols[1]);
293                                         gauge_t mnum = atof (cols[2]);
294                                         gauge_t lnum = atof (cols[3]);
295                                         load_submit (dent->d_name, snum, mnum, lnum);
296                                 }
297                         }
298                 } /* while (fgets) */
300                 if (fh != NULL)
301                 {
302                         fclose (fh);
303                         fh = NULL;
304                 }
306                 /* processes and memory usage */
307                 len = snprintf (file, BUFSIZE, PROCDIR "/%s/limit", dent->d_name);
308                 if ((len < 0) || (len >= BUFSIZE))
309                         continue;
311                 if (NULL == (fh = fopen (file, "r")))
312                         syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
314                 while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
315                 {
316                         char *type = "vs_memory";
317                         char *type_instance;
318                         gauge_t value;
320                         if (strsplit (buffer, cols, 2) < 2)
321                                 continue;
323                         if (0 == strcmp (cols[0], "PROC:"))
324                         {
325                                 type = "vs_processes";
326                                 type_instance = "";
327                                 value = atof (cols[1]);
328                         }
329                         else
330                         {
331                                 if (0 == strcmp (cols[0], "VM:"))
332                                         type_instance = "vm";
333                                 else if (0 == strcmp (cols[0], "VML:"))
334                                         type_instance = "vml";
335                                 else if (0 == strcmp (cols[0], "RSS:"))
336                                         type_instance = "rss";
337                                 else if (0 == strcmp (cols[0], "ANON:"))
338                                         type_instance = "anon";
339                                 else
340                                         continue;
342                                 value = atof (cols[1]) * pagesize;
343                         }
345                         submit_gauge (dent->d_name, type, type_instance, value);
346                 } /* while (fgets) */
348                 if (fh != NULL)
349                 {
350                         fclose (fh);
351                         fh = NULL;
352                 }
353         } /* while (readdir) */
355         closedir (proc);
357         return (0);
358 } /* int vserver_read */
359 #endif /* VSERVER_HAVE_READ */
361 void module_register (void)
363         plugin_register_data_set (&octets_ds);
364         plugin_register_data_set (&load_ds);
365         plugin_register_data_set (&threads_ds);
366         plugin_register_data_set (&processes_ds);
367         plugin_register_data_set (&memory_ds);
369 #if VSERVER_HAVE_READ
370         plugin_register_init ("vserver", vserver_init);
371         plugin_register_read ("vserver", vserver_read);
372 #endif /* VSERVER_HAVE_READ */
373 } /* void module_register(void) */
375 /* vim: set ts=4 sw=4 noexpandtab : */