contrib/collection.cgi: Added basic support for "postgresql" statistics.
[collectd.git] / src / nfs.c
1 /**
2  * collectd - src/nfs.c
3  * Copyright (C) 2005,2006  Jason Pepas
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; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Jason Pepas <cell at ices.utexas.edu>
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 #if !KERNEL_LINUX
28 # error "No applicable input method."
29 #endif
30
31 /*
32 see /proc/net/rpc/nfs
33 see http://www.missioncriticallinux.com/orph/NFS-Statistics
34
35 net x x x x
36 rpc_stat.netcnt         Not used; always zero.
37 rpc_stat.netudpcnt      Not used; always zero.
38 rpc_stat.nettcpcnt      Not used; always zero.
39 rpc_stat.nettcpconn     Not used; always zero.
40
41 rpc x x x
42 rpc_stat.rpccnt             The number of RPC calls.
43 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
44 rpc_stat.rpcauthrefresh     The number of credential refreshes.
45
46 proc2 x x x...
47 proc3 x x x...
48
49 Procedure   NFS Version NFS Version 3
50 Number      Procedures  Procedures
51
52 0           null        null
53 1           getattr     getattr
54 2           setattr     setattr
55 3           root        lookup
56 4           lookup      access
57 5           readlink    readlink
58 6           read        read
59 7           wrcache     write
60 8           write       create
61 9           create      mkdir
62 10          remove      symlink
63 11          rename      mknod
64 12          link        remove
65 13          symlink     rmdir
66 14          mkdir       rename
67 15          rmdir       link
68 16          readdir     readdir
69 17          fsstat      readdirplus
70 18                      fsstat
71 19                      fsinfo
72 20                      pathconf
73 21                      commit
74 */
75
76 static const char *nfs2_procedures_names[] =
77 {
78         "null",
79         "getattr",
80         "setattr",
81         "root",
82         "lookup",
83         "readlink",
84         "read",
85         "wrcache",
86         "write",
87         "create",
88         "remove",
89         "rename",
90         "link",
91         "symlink",
92         "mkdir",
93         "rmdir",
94         "readdir",
95         "fsstat",
96         NULL
97 };
98 static int nfs2_procedures_names_num = 18;
99
100 static const char *nfs3_procedures_names[] =
101 {
102         "null",
103         "getattr",
104         "setattr",
105         "lookup",
106         "access",
107         "readlink",
108         "read",
109         "write",
110         "create",
111         "mkdir",
112         "symlink",
113         "mknod",
114         "remove",
115         "rmdir",
116         "rename",
117         "link",
118         "readdir",
119         "readdirplus",
120         "fsstat",
121         "fsinfo",
122         "pathconf",
123         "commit",
124         NULL
125 };
126 static int nfs3_procedures_names_num = 22;
127
128 #if HAVE_LIBKSTAT && 0
129 extern kstat_ctl_t *kc;
130 static kstat_t *nfs2_ksp_client;
131 static kstat_t *nfs2_ksp_server;
132 static kstat_t *nfs3_ksp_client;
133 static kstat_t *nfs3_ksp_server;
134 static kstat_t *nfs4_ksp_client;
135 static kstat_t *nfs4_ksp_server;
136 #endif
137
138 /* Possibly TODO: NFSv4 statistics */
139
140 #if 0
141 static int nfs_init (void)
142 {
143 #if HAVE_LIBKSTAT && 0
144         kstat_t *ksp_chain;
145
146         nfs2_ksp_client = NULL;
147         nfs2_ksp_server = NULL;
148         nfs3_ksp_client = NULL;
149         nfs3_ksp_server = NULL;
150         nfs4_ksp_client = NULL;
151         nfs4_ksp_server = NULL;
152         
153         if (kc == NULL)
154                 return;
155
156         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
157                         ksp_chain = ksp_chain->ks_next)
158         {
159                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
160                         continue;
161                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
162                         nfs2_ksp_server = ksp_chain;
163                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
164                         nfs3_ksp_server = ksp_chain;
165                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
166                         nfs4_ksp_server = ksp_chain;
167                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
168                         nfs2_ksp_client = ksp_chain;
169                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
170                         nfs3_ksp_client = ksp_chain;
171                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
172                         nfs4_ksp_client = ksp_chain;
173         }
174 #endif
175
176         return (0);
177 } /* int nfs_init */
178 #endif
179
180 #define BUFSIZE 1024
181 static void nfs_procedures_submit (const char *plugin_instance,
182                 unsigned long long *val, const char **names, int len)
183 {
184         value_t values[1];
185         value_list_t vl = VALUE_LIST_INIT;
186         int i;
187
188         vl.values = values;
189         vl.values_len = 1;
190         vl.time = time (NULL);
191         strcpy (vl.host, hostname_g);
192         strcpy (vl.plugin, "nfs");
193         sstrncpy (vl.plugin_instance, plugin_instance,
194                         sizeof (vl.plugin_instance));
195         strcpy (vl.type, "nfs_procedure");
196
197         for (i = 0; i < len; i++)
198         {
199                 values[0].counter = val[i];
200                 sstrncpy (vl.type_instance, names[i],
201                                 sizeof (vl.type_instance));
202                 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
203                                 vl.plugin, vl.plugin_instance,
204                                 vl.type_instance, val[i]);
205                 plugin_dispatch_values (&vl);
206         }
207 } /* void nfs_procedures_submit */
208
209 static void nfs_read_stats_file (FILE *fh, char *inst)
210 {
211         char buffer[BUFSIZE];
212
213         char plugin_instance[DATA_MAX_NAME_LEN];
214
215         char *fields[48];
216         int numfields = 0;
217
218         if (fh == NULL)
219                 return;
220
221         while (fgets (buffer, BUFSIZE, fh) != NULL)
222         {
223                 numfields = strsplit (buffer, fields, 48);
224
225                 if (((numfields - 2) != nfs2_procedures_names_num)
226                                 && ((numfields - 2)
227                                         != nfs3_procedures_names_num))
228                         continue;
229
230                 if (strcmp (fields[0], "proc2") == 0)
231                 {
232                         int i;
233                         unsigned long long *values;
234
235                         if ((numfields - 2) != nfs2_procedures_names_num)
236                         {
237                                 WARNING ("nfs plugin: Wrong "
238                                                 "number of fields (= %i) "
239                                                 "for NFSv2 statistics.",
240                                                 numfields - 2);
241                                 continue;
242                         }
243
244                         ssnprintf (plugin_instance, sizeof (plugin_instance),
245                                         "v2%s", inst);
246
247                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
248                         if (values == NULL)
249                         {
250                                 char errbuf[1024];
251                                 ERROR ("nfs plugin: malloc "
252                                                 "failed: %s",
253                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
254                                 continue;
255                         }
256
257                         for (i = 0; i < nfs2_procedures_names_num; i++)
258                                 values[i] = atoll (fields[i + 2]);
259
260                         nfs_procedures_submit (plugin_instance, values,
261                                         nfs2_procedures_names,
262                                         nfs2_procedures_names_num);
263
264                         free (values);
265                 }
266                 else if (strncmp (fields[0], "proc3", 5) == 0)
267                 {
268                         int i;
269                         unsigned long long *values;
270
271                         if ((numfields - 2) != nfs3_procedures_names_num)
272                         {
273                                 WARNING ("nfs plugin: Wrong "
274                                                 "number of fields (= %i) "
275                                                 "for NFSv3 statistics.",
276                                                 numfields - 2);
277                                 continue;
278                         }
279
280                         ssnprintf (plugin_instance, sizeof (plugin_instance),
281                                         "v3%s", inst);
282
283                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
284                         if (values == NULL)
285                         {
286                                 char errbuf[1024];
287                                 ERROR ("nfs plugin: malloc "
288                                                 "failed: %s",
289                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
290                                 continue;
291                         }
292
293                         for (i = 0; i < nfs3_procedures_names_num; i++)
294                                 values[i] = atoll (fields[i + 2]);
295
296                         nfs_procedures_submit (plugin_instance, values,
297                                         nfs3_procedures_names,
298                                         nfs3_procedures_names_num);
299
300                         free (values);
301                 }
302         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
303 } /* void nfs_read_stats_file */
304 #undef BUFSIZE
305
306 #if HAVE_LIBKSTAT && 0
307 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
308 {
309         unsigned long long values[18];
310
311         values[0] = get_kstat_value (ksp, "null");
312         values[1] = get_kstat_value (ksp, "getattr");
313         values[2] = get_kstat_value (ksp, "setattr");
314         values[3] = get_kstat_value (ksp, "root");
315         values[4] = get_kstat_value (ksp, "lookup");
316         values[5] = get_kstat_value (ksp, "readlink");
317         values[6] = get_kstat_value (ksp, "read");
318         values[7] = get_kstat_value (ksp, "wrcache");
319         values[8] = get_kstat_value (ksp, "write");
320         values[9] = get_kstat_value (ksp, "create");
321         values[10] = get_kstat_value (ksp, "remove");
322         values[11] = get_kstat_value (ksp, "rename");
323         values[12] = get_kstat_value (ksp, "link");
324         values[13] = get_kstat_value (ksp, "symlink");
325         values[14] = get_kstat_value (ksp, "mkdir");
326         values[15] = get_kstat_value (ksp, "rmdir");
327         values[16] = get_kstat_value (ksp, "readdir");
328         values[17] = get_kstat_value (ksp, "statfs");
329
330         nfs2_procedures_submit (values, inst);
331 }
332 #endif
333
334 static int nfs_read (void)
335 {
336         FILE *fh;
337
338         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
339         {
340                 nfs_read_stats_file (fh, "client");
341                 fclose (fh);
342         }
343
344         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
345         {
346                 nfs_read_stats_file (fh, "server");
347                 fclose (fh);
348         }
349
350 #if HAVE_LIBKSTAT && 0
351         if (nfs2_ksp_client != NULL)
352                 nfs2_read_kstat (nfs2_ksp_client, "client");
353         if (nfs2_ksp_server != NULL)
354                 nfs2_read_kstat (nfs2_ksp_server, "server");
355 #endif /* defined(HAVE_LIBKSTAT) */
356
357         return (0);
358 }
359
360 void module_register (void)
361 {
362         plugin_register_read ("nfs", nfs_read);
363 } /* void module_register */