Added `Handler_*' support to the `mysql' plugin
[collectd.git] / src / mysql.c
1 /**
2  * collectd - src/mysql.c
3  * Copyright (C) 2005  Florian octo Forster
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  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "configfile.h"
27
28 #ifdef HAVE_MYSQL_MYSQL_H
29 #include <mysql/mysql.h>
30 #endif
31
32 #define MODULE_NAME "mysql"
33
34 #if COLLECT_LIBMYSQL
35 # define MYSQL_HAVE_READ 1
36 #else
37 # define MYSQL_HAVE_READ 0
38 #endif
39
40 #define BUFSIZE 512
41
42 static char *host = "localhost";
43 static char *user;
44 static char *pass;
45 static char *db = NULL;
46
47 static char  init_suceeded = 0;
48
49 static char *commands_file = "mysql/mysql_commands-%s.rrd";
50 static char *handler_file = "mysql/mysql_handler-%s.rrd";
51 static char *traffic_file  = "traffic-mysql.rrd";
52
53 static char *commands_ds_def[] =
54 {
55         "DS:value:COUNTER:25:0:U",
56         NULL
57 };
58 static int commands_ds_num = 1;
59
60 static char *handler_ds_def[] =
61 {
62         "DS:value:COUNTER:25:0:U",
63         NULL
64 };
65 static int handler_ds_num = 1;
66
67 static char *traffic_ds_def[] =
68 {
69         "DS:incoming:COUNTER:25:0:U",
70         "DS:outgoing:COUNTER:25:0:U",
71         NULL
72 };
73 static int traffic_ds_num = 2;
74
75 static char *config_keys[] =
76 {
77         "Host",
78         "User",
79         "Password",
80         "Database",
81         NULL
82 };
83 static int config_keys_num = 4;
84
85 #if MYSQL_HAVE_READ
86 static MYSQL *getconnection (void)
87 {
88         static MYSQL *con;
89         static int    state;
90
91         if (state != 0)
92         {
93                 int err;
94                 if ((err = mysql_ping (con)) != 0)
95                 {
96                         syslog (LOG_WARNING, "mysql_ping failed: %s", mysql_error (con));
97                         state = 0;
98                 }
99                 else
100                 {
101                         state = 1;
102                         return (con);
103                 }
104         }
105
106         if ((con = mysql_init (con)) == NULL)
107         {
108                 syslog (LOG_ERR, "mysql_init failed: %s", mysql_error (con));
109                 state = 0;
110                 return (NULL);
111         }
112
113         if (mysql_real_connect (con, host, user, pass, db, 0, NULL, 0) == NULL)
114         {
115                 syslog (LOG_ERR, "mysql_real_connect failed: %s", mysql_error (con));
116                 state = 0;
117                 return (NULL);
118         }
119         else
120         {
121                 state = 1;
122                 return (con);
123         }
124 } /* static MYSQL *getconnection (void) */
125 #endif /* MYSQL_HAVE_READ */
126
127 static void init (void)
128 {
129 #if MYSQL_HAVE_READ
130         if (getconnection () != NULL)
131                 init_suceeded = 1;
132         else
133         {
134                 syslog (LOG_ERR, "The `mysql' plugin will be disabled because `init' failed to connect to `%s'", host);
135                 init_suceeded = 0;
136         }
137 #endif /* MYSQL_HAVE_READ */
138
139         return;
140 }
141
142 static int config (char *key, char *value)
143 {
144         if (strcasecmp (key, "host") == 0)
145                 return ((host = strdup (value)) == NULL ? 1 : 0);
146         else if (strcasecmp (key, "user") == 0)
147                 return ((user = strdup (value)) == NULL ? 1 : 0);
148         else if (strcasecmp (key, "password") == 0)
149                 return ((pass = strdup (value)) == NULL ? 1 : 0);
150         else if (strcasecmp (key, "database") == 0)
151                 return ((db = strdup (value)) == NULL ? 1 : 0);
152         else
153                 return (-1);
154 }
155
156 static void commands_write (char *host, char *inst, char *val)
157 {
158         char buf[BUFSIZE];
159
160         if (snprintf (buf, BUFSIZE, commands_file, inst) >= BUFSIZE)
161                 return;
162
163         rrd_update_file (host, buf, val, commands_ds_def, commands_ds_num);
164 }
165
166 static void handler_write (char *host, char *inst, char *val)
167 {
168         char buf[BUFSIZE];
169
170         if (snprintf (buf, BUFSIZE, handler_file, inst) >= BUFSIZE)
171                 return;
172
173         rrd_update_file (host, buf, val, handler_ds_def, handler_ds_num);
174 }
175
176 static void traffic_write (char *host, char *inst, char *val)
177 {
178         rrd_update_file (host, traffic_file, val, traffic_ds_def, traffic_ds_num);
179 }
180
181 #if MYSQL_HAVE_READ
182 static void commands_submit (char *inst, unsigned long long value)
183 {
184         char buf[BUFSIZE];
185         int  status;
186
187         status = snprintf (buf, BUFSIZE, "%u:%llu", (unsigned int) curtime, value);
188
189         if (status < 0)
190         {
191                 syslog (LOG_ERR, "snprintf failed");
192                 return;
193         }
194         else if (status >= BUFSIZE)
195         {
196                 syslog (LOG_WARNING, "snprintf was truncated");
197                 return;
198         }
199
200         plugin_submit ("mysql_commands", inst, buf);
201 }
202
203 static void handler_submit (char *inst, unsigned long long value)
204 {
205         char buf[BUFSIZE];
206         int  status;
207
208         status = snprintf (buf, BUFSIZE, "%u:%llu", (unsigned int) curtime, value);
209
210         if (status < 0)
211         {
212                 syslog (LOG_ERR, "snprintf failed");
213                 return;
214         }
215         else if (status >= BUFSIZE)
216         {
217                 syslog (LOG_WARNING, "snprintf was truncated");
218                 return;
219         }
220
221         plugin_submit ("mysql_handler", inst, buf);
222 }
223
224 static void traffic_submit (unsigned long long incoming,
225                 unsigned long long outgoing)
226 {
227         char buf[BUFSIZE];
228         int  status;
229
230         status = snprintf (buf, BUFSIZE, "%u:%llu:%llu", (unsigned int) curtime,
231                         incoming, outgoing);
232
233         if (status < 0)
234         {
235                 syslog (LOG_ERR, "snprintf failed");
236                 return;
237         }
238         else if (status >= BUFSIZE)
239         {
240                 syslog (LOG_WARNING, "snprintf was truncated");
241                 return;
242         }
243
244         plugin_submit ("mysql_traffic", "-", buf);
245 }
246
247 static void mysql_read (void)
248 {
249         MYSQL     *con;
250         MYSQL_RES *res;
251         MYSQL_ROW  row;
252         char      *query;
253         int        query_len;
254         int        field_num;
255
256         unsigned long long traffic_incoming = 0LL;
257         unsigned long long traffic_outgoing = 0LL;
258
259         if (init_suceeded == 0)
260                 return;
261
262         /* An error message will have been printed in this case */
263         if ((con = getconnection ()) == NULL)
264                 return;
265
266         query = "SHOW STATUS";
267         query_len = strlen (query);
268
269         if (mysql_real_query (con, query, query_len))
270         {
271                 syslog (LOG_ERR, "mysql_real_query failed: %s\n", mysql_error (con));
272                 return;
273         }
274
275         if ((res = mysql_store_result (con)) == NULL)
276         {
277                 syslog (LOG_ERR, "mysql_store_result failed: %s\n", mysql_error (con));
278                 return;
279         }
280
281         field_num = mysql_num_fields (res);
282         while ((row = mysql_fetch_row (res)))
283         {
284                 char *key;
285                 unsigned long long val;
286
287                 key = row[0];
288                 val = atoll (row[1]);
289
290                 if (val == 0ULL)
291                         continue;
292
293                 if (strncmp (key, "Com_", 4) == 0)
294                 {
295                         /* Ignore `prepared statements' */
296                         if (strncmp (key, "Com_stmt_", 9) != 0)
297                                 commands_submit (key + 4, val);
298                 }
299                 else if (strncmp (key, "Handler_", 8) == 0)
300                 {
301                         handler_submit (key + 8, val);
302                 }
303                 else if (strncmp (key, "Bytes_", 6) == 0)
304                 {
305                         if (strcmp (key, "Bytes_received") == 0)
306                                 traffic_incoming += val;
307                         else if (strcmp (key, "Bytes_sent") == 0)
308                                 traffic_outgoing += val;
309                 }
310         }
311         mysql_free_result (res); res = NULL;
312
313         traffic_submit  (traffic_incoming, traffic_outgoing);
314
315         /* mysql_close (con); */
316
317         return;
318 }
319 #else
320 # define mysql_read NULL
321 #endif /* MYSQL_HAVE_READ */
322
323 void module_register (void)
324 {
325         plugin_register (MODULE_NAME, init, mysql_read, NULL);
326         plugin_register ("mysql_commands", NULL, NULL, commands_write);
327         plugin_register ("mysql_handler", NULL, NULL, handler_write);
328         plugin_register ("mysql_traffic", NULL, NULL, traffic_write);
329         cf_register (MODULE_NAME, config, config_keys, config_keys_num);
330 }
331
332 #undef BUFSIZE
333 #undef MODULE_NAME