fscache plugin: Add new plugin for Linux' file-system based caching framework.
[collectd.git] / src / fscache.c
1 /**
2  * collectd - src/fscache.c
3  * Copyright (C) 2009 Edward "Koko" Konetzko
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  *   Edward "Koko" Konetzko <konetzed at quixoticagony.com>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include <stdio.h>  /* a header needed for FILE */
26 #include <string.h> /* a header needed for scanf function */
27 #include <stdlib.h> /* used for atoi */
28
29
30 #if !KERNEL_LINUX
31 # error "This module only supports the Linux implementation of fscache"
32 #endif
33
34 #define BUFSIZE 1024
35
36 /*
37 see /proc/fs/fscache/stats
38 see Documentation/filesystems/caching/fscache.txt in linux kernel >= 2.6.30
39
40 This shows counts of a number of events that can happen in FS-Cache:
41
42 CLASS   EVENT   MEANING
43 ======= ======= =======================================================
44 Cookies idx=N   Number of index cookies allocated
45         dat=N   Number of data storage cookies allocated
46         spc=N   Number of special cookies allocated
47 Objects alc=N   Number of objects allocated
48         nal=N   Number of object allocation failures
49         avl=N   Number of objects that reached the available state
50         ded=N   Number of objects that reached the dead state
51 ChkAux  non=N   Number of objects that didn't have a coherency check
52         ok=N    Number of objects that passed a coherency check
53         upd=N   Number of objects that needed a coherency data update
54         obs=N   Number of objects that were declared obsolete
55 Pages   mrk=N   Number of pages marked as being cached
56         unc=N   Number of uncache page requests seen
57 Acquire n=N Number of acquire cookie requests seen
58         nul=N   Number of acq reqs given a NULL parent
59         noc=N   Number of acq reqs rejected due to no cache available
60         ok=N    Number of acq reqs succeeded
61         nbf=N   Number of acq reqs rejected due to error
62         oom=N   Number of acq reqs failed on ENOMEM
63 Lookups n=N Number of lookup calls made on cache backends
64         neg=N   Number of negative lookups made
65         pos=N   Number of positive lookups made
66         crt=N   Number of objects created by lookup
67 Updates n=N Number of update cookie requests seen
68         nul=N   Number of upd reqs given a NULL parent
69         run=N   Number of upd reqs granted CPU time
70 Relinqs n=N Number of relinquish cookie requests seen
71         nul=N   Number of rlq reqs given a NULL parent
72         wcr=N   Number of rlq reqs waited on completion of creation
73 AttrChg n=N Number of attribute changed requests seen
74         ok=N    Number of attr changed requests queued
75         nbf=N   Number of attr changed rejected -ENOBUFS
76         oom=N   Number of attr changed failed -ENOMEM
77         run=N   Number of attr changed ops given CPU time
78 Allocs  n=N Number of allocation requests seen
79         ok=N    Number of successful alloc reqs
80         wt=N    Number of alloc reqs that waited on lookup completion
81         nbf=N   Number of alloc reqs rejected -ENOBUFS
82         ops=N   Number of alloc reqs submitted
83         owt=N   Number of alloc reqs waited for CPU time
84 Retrvls n=N Number of retrieval (read) requests seen
85         ok=N    Number of successful retr reqs
86         wt=N    Number of retr reqs that waited on lookup completion
87         nod=N   Number of retr reqs returned -ENODATA
88         nbf=N   Number of retr reqs rejected -ENOBUFS
89         int=N   Number of retr reqs aborted -ERESTARTSYS
90         oom=N   Number of retr reqs failed -ENOMEM
91         ops=N   Number of retr reqs submitted
92         owt=N   Number of retr reqs waited for CPU time
93 Stores  n=N Number of storage (write) requests seen
94         ok=N    Number of successful store reqs
95         agn=N   Number of store reqs on a page already pending storage
96         nbf=N   Number of store reqs rejected -ENOBUFS
97         oom=N   Number of store reqs failed -ENOMEM
98         ops=N   Number of store reqs submitted
99         run=N   Number of store reqs granted CPU time
100 Ops pend=N  Number of times async ops added to pending queues
101         run=N   Number of times async ops given CPU time
102         enq=N   Number of times async ops queued for processing
103         dfr=N   Number of async ops queued for deferred release
104         rel=N   Number of async ops released
105         gc=N    Number of deferred-release async ops garbage collected
106
107 63 events to collect in 13 groups
108 */
109
110 static int fscache_number_of_values = 62;
111
112 struct fscache_values {
113     char name[20];
114     unsigned long long value;
115 };  /*end struct fscache_values */
116
117 static void fscache_submit(struct fscache_values submit_values[]){
118 /*submit logic goes here!!!!!*/
119
120     value_t values[1];
121     value_list_t vl = VALUE_LIST_INIT;
122     int i;
123
124     vl.values = values;
125     vl.values_len = 1;
126     sstrncpy(vl.host, hostname_g, sizeof(vl.host));
127     sstrncpy(vl.plugin, "fscache", sizeof(vl.plugin));
128     sstrncpy(vl.plugin_instance, "fscache",
129             sizeof(vl.plugin_instance));
130     sstrncpy(vl.type, "fscache_stat", sizeof(vl.type));
131
132     for (i = 0; i < fscache_number_of_values; i++){
133         values[0].counter = submit_values[i].value;
134         sstrncpy(vl.type_instance, submit_values[i].name,
135                 sizeof(vl.type_instance));
136         DEBUG("%s-%s/fscache-%s = %llu",
137                 vl.plugin, vl.plugin_instance,
138                 vl.type_instance, submit_values[i].value);
139         plugin_dispatch_values(&vl);
140     }
141 }
142
143 static void fscache_read_stats_file(FILE *fh){
144     int forcount = 0;
145     int count = 0;
146     int start = 0;
147     int numfields = 0;
148     int valuecounter = 0;
149     char filebuffer[BUFSIZE];
150     char valuebuffer[BUFSIZE];
151     char valuename[BUFSIZE];
152     char valuevalue[BUFSIZE];
153     char sectionbuffer[BUFSIZE];
154     char tempstring[BUFSIZE];
155     char *ptrfilebuffer = filebuffer;
156     char *position = NULL;
157     char *fields[fscache_number_of_values];
158     struct fscache_values values[fscache_number_of_values];
159
160     /* Read file line by line */
161     while( fgets( filebuffer, BUFSIZE, fh)!= NULL){
162         /*skip first line and split file on : */
163         if (count != 0){
164             position = strchr(filebuffer,':');
165             start = strlen(filebuffer) - 1;
166             filebuffer[start] = '\0';
167             /* : is located at value 8, +1 to remove space */
168             strncpy(valuebuffer, ptrfilebuffer+9, start);
169             /*store section info for later */
170             strncpy(sectionbuffer, ptrfilebuffer, position - filebuffer);
171             position = strchr(sectionbuffer, ' ');
172             if (position != NULL){
173                 sectionbuffer[position-sectionbuffer] = '\0';
174             }
175
176             /*split rest of line by space and then split that via =*/
177             numfields = strsplit ( valuebuffer, fields,
178                     fscache_number_of_values);
179             for( forcount = 0; forcount < numfields; forcount++ ){
180                 char *field = fields[forcount];
181                 memset(valuename,'\0',sizeof(valuename));
182                 position = strchr(field, '=');
183                 /* Test to see if we actually have a metric to split on
184                  * and assign the values to the struct array */
185                 if (position != NULL){
186                     strncpy(valuename, field, position - field);
187                     strncpy(valuevalue, field + (position - field + 1),
188                             strlen(field));
189                     memset(tempstring,'\0',sizeof(tempstring));
190                     strncat(tempstring,sectionbuffer,sizeof(tempstring));
191                     strncat(tempstring,"_",1);
192                     strncat(tempstring,valuename, sizeof(tempstring));
193                     memset(values[valuecounter].name,'\0',
194                             sizeof(values[valuecounter].name));
195                     strncpy(values[valuecounter].name,tempstring,
196                             sizeof(values[valuecounter].name));
197                     values[valuecounter].value = atoll(valuevalue);
198                 }
199             valuecounter++;
200             }
201         }
202     count++;
203     }
204     fscache_submit(values);
205 }
206
207 static int fscache_read (void){
208     FILE *fh;
209     fh = fopen("/proc/fs/fscache/stats", "r");
210     if (fh != NULL){
211         fscache_read_stats_file(fh);
212         fclose(fh);
213
214     }else{
215         printf("cant open file\n");
216         return (-1);
217     }
218     return (0);
219 }
220
221 void module_register (void)
222 {
223     plugin_register_read ("fscache", fscache_read);
224 } /* void module_register */
225