Merge branch 'ff/types' into collectd-4
[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  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 #include <dirent.h>
28 #include <sys/types.h>
29
30 #define BUFSIZE 512
31
32 #define MODULE_NAME "vserver"
33 #define PROCDIR "/proc/virtual"
34
35 #if defined(KERNEL_LINUX)
36 # define VSERVER_HAVE_READ 1
37 #else
38 # define VSERVER_HAVE_READ 0
39 #endif /* defined(KERNEL_LINUX) */
40
41 #if VSERVER_HAVE_READ
42 static int pagesize = 0;
43
44 static int vserver_init (void)
45 {
46         /* XXX Should we check for getpagesize () in configure?
47          * What's the right thing to do, if there is no getpagesize ()? */
48         pagesize = getpagesize ();
49
50         return (0);
51 } /* static void vserver_init(void) */
52
53 static void traffic_submit (const char *plugin_instance,
54                 const char *type_instance, counter_t rx, counter_t tx)
55 {
56         value_t values[2];
57         value_list_t vl = VALUE_LIST_INIT;
58
59         values[0].counter = rx;
60         values[1].counter = tx;
61
62         vl.values = values;
63         vl.values_len = STATIC_ARRAY_SIZE (values);
64         vl.time = time (NULL);
65         strcpy (vl.host, hostname_g);
66         strcpy (vl.plugin, "vserver");
67         strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
68         strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
69
70         plugin_dispatch_values ("if_octets", &vl);
71 } /* void traffic_submit */
72
73 static void load_submit (const char *plugin_instance,
74                 gauge_t snum, gauge_t mnum, gauge_t lnum)
75 {
76         value_t values[3];
77         value_list_t vl = VALUE_LIST_INIT;
78
79         values[0].gauge = snum;
80         values[1].gauge = mnum;
81         values[2].gauge = lnum;
82
83         vl.values = values;
84         vl.values_len = STATIC_ARRAY_SIZE (values);
85         vl.time = time (NULL);
86         strcpy (vl.host, hostname_g);
87         strcpy (vl.plugin, "vserver");
88         strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
89
90         plugin_dispatch_values ("load", &vl);
91 }
92
93 static void submit_gauge (const char *plugin_instance, const char *type,
94                 const char *type_instance, gauge_t value)
95
96 {
97         value_t values[1];
98         value_list_t vl = VALUE_LIST_INIT;
99
100         values[0].gauge = value;
101
102         vl.values = values;
103         vl.values_len = STATIC_ARRAY_SIZE (values);
104         vl.time = time (NULL);
105         strcpy (vl.host, hostname_g);
106         strcpy (vl.plugin, "vserver");
107         strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
108         strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
109
110         plugin_dispatch_values (type, &vl);
111 } /* void submit_gauge */
112
113 static inline long long __get_sock_bytes(const char *s)
114 {
115         while (s[0] != '/')
116                 ++s;
117
118         /* Remove '/' */
119         ++s;
120         return atoll(s);
121 }
122
123 static int vserver_read (void)
124 {
125         DIR                     *proc;
126         struct dirent   *dent; /* 42 */
127
128         errno = 0;
129         if (NULL == (proc = opendir (PROCDIR)))
130         {
131                 char errbuf[1024];
132                 ERROR ("vserver plugin: fopen (%s): %s", PROCDIR, 
133                                 sstrerror (errno, errbuf, sizeof (errbuf)));
134                 return (-1);
135         }
136
137         while (NULL != (dent = readdir (proc)))
138         {
139                 int  len;
140                 char file[BUFSIZE];
141
142                 FILE *fh;
143                 char buffer[BUFSIZE];
144
145                 char *cols[4];
146
147                 if (dent->d_name[0] == '.')
148                         continue;
149
150                 /* This is not a directory */
151                 if (dent->d_type != DT_DIR)
152                         continue;
153
154                 /* socket message accounting */
155                 len = snprintf (file, BUFSIZE, PROCDIR "/%s/cacct", dent->d_name);
156                 if ((len < 0) || (len >= BUFSIZE))
157                         continue;
158
159                 if (NULL == (fh = fopen (file, "r")))
160                 {
161                         char errbuf[1024];
162                         ERROR ("Cannot open '%s': %s", file,
163                                         sstrerror (errno, errbuf, sizeof (errbuf)));
164                 }
165
166                 while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
167                 {
168                         counter_t rx;
169                         counter_t tx;
170                         char *type_instance;
171
172                         if (strsplit (buffer, cols, 4) < 4)
173                                 continue;
174
175                         if (0 == strcmp (cols[0], "UNIX:"))
176                                 type_instance = "unix";
177                         else if (0 == strcmp (cols[0], "INET:"))
178                                 type_instance = "inet";
179                         else if (0 == strcmp (cols[0], "INET6:"))
180                                 type_instance = "inet6";
181                         else if (0 == strcmp (cols[0], "OTHER:"))
182                                 type_instance = "other";
183                         else if (0 == strcmp (cols[0], "UNSPEC:"))
184                                 type_instance = "unspec";
185                         else
186                                 continue;
187
188                         rx = __get_sock_bytes (cols[1]);
189                         tx = __get_sock_bytes (cols[2]);
190                         /* cols[3] == errors */
191
192                         traffic_submit (dent->d_name, type_instance, rx, tx);
193                 } /* while (fgets) */
194
195                 if (fh != NULL)
196                 {
197                         fclose (fh);
198                         fh = NULL;
199                 }
200
201                 /* thread information and load */
202                 len = snprintf (file, BUFSIZE, PROCDIR "/%s/cvirt", dent->d_name);
203                 if ((len < 0) || (len >= BUFSIZE))
204                         continue;
205
206                 if (NULL == (fh = fopen (file, "r")))
207                 {
208                         char errbuf[1024];
209                         ERROR ("Cannot open '%s': %s", file,
210                                         sstrerror (errno, errbuf, sizeof (errbuf)));
211                 }
212
213                 while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
214                 {
215                         int n = strsplit (buffer, cols, 4);
216
217                         if (2 == n)
218                         {
219                                 char   *type_instance;
220                                 gauge_t value;
221
222                                 if (0 == strcmp (cols[0], "nr_threads:"))
223                                         type_instance = "total";
224                                 else if (0 == strcmp (cols[0], "nr_running:"))
225                                         type_instance = "running";
226                                 else if (0 == strcmp (cols[0], "nr_unintr:"))
227                                         type_instance = "uninterruptable";
228                                 else if (0 == strcmp (cols[0], "nr_onhold:"))
229                                         type_instance = "onhold";
230                                 else
231                                         continue;
232
233                                 value = atof (cols[1]);
234                                 submit_gauge (dent->d_name, "vs_threads", type_instance, value);
235                         }
236                         else if (4 == n) {
237                                 if (0 == strcmp (cols[0], "loadavg:"))
238                                 {
239                                         gauge_t snum = atof (cols[1]);
240                                         gauge_t mnum = atof (cols[2]);
241                                         gauge_t lnum = atof (cols[3]);
242                                         load_submit (dent->d_name, snum, mnum, lnum);
243                                 }
244                         }
245                 } /* while (fgets) */
246
247                 if (fh != NULL)
248                 {
249                         fclose (fh);
250                         fh = NULL;
251                 }
252
253                 /* processes and memory usage */
254                 len = snprintf (file, BUFSIZE, PROCDIR "/%s/limit", dent->d_name);
255                 if ((len < 0) || (len >= BUFSIZE))
256                         continue;
257
258                 if (NULL == (fh = fopen (file, "r")))
259                 {
260                         char errbuf[1024];
261                         ERROR ("Cannot open '%s': %s", file,
262                                         sstrerror (errno, errbuf, sizeof (errbuf)));
263                 }
264
265                 while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
266                 {
267                         char *type = "vs_memory";
268                         char *type_instance;
269                         gauge_t value;
270
271                         if (strsplit (buffer, cols, 2) < 2)
272                                 continue;
273
274                         if (0 == strcmp (cols[0], "PROC:"))
275                         {
276                                 type = "vs_processes";
277                                 type_instance = "";
278                                 value = atof (cols[1]);
279                         }
280                         else
281                         {
282                                 if (0 == strcmp (cols[0], "VM:"))
283                                         type_instance = "vm";
284                                 else if (0 == strcmp (cols[0], "VML:"))
285                                         type_instance = "vml";
286                                 else if (0 == strcmp (cols[0], "RSS:"))
287                                         type_instance = "rss";
288                                 else if (0 == strcmp (cols[0], "ANON:"))
289                                         type_instance = "anon";
290                                 else
291                                         continue;
292
293                                 value = atof (cols[1]) * pagesize;
294                         }
295
296                         submit_gauge (dent->d_name, type, type_instance, value);
297                 } /* while (fgets) */
298
299                 if (fh != NULL)
300                 {
301                         fclose (fh);
302                         fh = NULL;
303                 }
304         } /* while (readdir) */
305
306         closedir (proc);
307
308         return (0);
309 } /* int vserver_read */
310 #endif /* VSERVER_HAVE_READ */
311
312 void module_register (void)
313 {
314 #if VSERVER_HAVE_READ
315         plugin_register_init ("vserver", vserver_init);
316         plugin_register_read ("vserver", vserver_read);
317 #endif /* VSERVER_HAVE_READ */
318 } /* void module_register(void) */
319
320 /* vim: set ts=4 sw=4 noexpandtab : */