root/src/modules/mysql.c

Revision 929c7f037a23c52a0af8d9da9779dc192094e041, 8.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

fix event name C&P error

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <assert.h>
12 #include <math.h>
13
14 #include "noit_module.h"
15 #include "noit_check.h"
16 #include "noit_check_tools.h"
17 #include "utils/noit_log.h"
18 #include "utils/noit_hash.h"
19
20 #include <mysql.h>
21
22 typedef struct {
23   noit_module_t *self;
24   noit_check_t *check;
25   MYSQL *conn;
26   MYSQL_RES *result;
27   int rv;
28   noit_hash_table attrs;
29   int timed_out;
30   char *error;
31 } mysql_check_info_t;
32
33 static noit_log_stream_t nlerr = NULL;
34 static noit_log_stream_t nldeb = NULL;
35
36 static void mysql_cleanup(noit_module_t *self, noit_check_t *check) {
37   mysql_check_info_t *ci = check->closure;
38   if(ci) {
39     if(ci->result) mysql_free_result(ci->result);
40     if(ci->conn) mysql_close(ci->conn);
41     noit_check_release_attrs(&ci->attrs);
42     if(ci->error) free(ci->error);
43     memset(ci, 0, sizeof(*ci));
44   }
45 }
46 static void mysql_log_results(noit_module_t *self, noit_check_t *check) {
47   stats_t current;
48   struct timeval duration;
49   mysql_check_info_t *ci = check->closure;
50
51   noit_check_stats_clear(&current);
52
53   gettimeofday(&current.whence, NULL);
54   sub_timeval(current.whence, check->last_fire_time, &duration);
55   current.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000;
56   current.available = NP_UNAVAILABLE;
57   current.state = NP_BAD;
58   if(ci->error) current.status = ci->error;
59   else if(ci->timed_out) current.status = "timeout";
60   else if(ci->rv == 0) {
61     current.available = NP_AVAILABLE;
62     current.state = NP_GOOD;
63     current.status = "no rows, ok";
64   }
65   else {
66     current.available = NP_AVAILABLE;
67     current.state = NP_GOOD;
68     current.status = "got rows, ok";
69   }
70
71   if(ci->rv > 0) {
72     /* metrics */
73     int nrows, ncols, i, j;
74     nrows = ci->rv;
75     ncols = mysql_num_fields(ci->result);
76     MYSQL_FIELD *cdesc = mysql_fetch_fields(ci->result);
77     for (i=0; i<nrows; i++) {
78       noitL(nldeb, "mysql: row %d [%d cols]:\n", i, ncols);
79       if(ncols<2) continue;
80       MYSQL_ROW row = mysql_fetch_row(ci->result);
81       if(NULL == row[0]) continue;
82       for (j=1; j<ncols; j++) {
83         enum enum_field_types coltype;
84         int iv, *piv;
85         int64_t lv, *plv;
86         double dv, *pdv;
87         char *sv;
88         char mname[128];
89  
90         snprintf(mname, sizeof(mname), "%s`%s", row[0], cdesc[j].name);
91         coltype = cdesc[j].type;
92         noitL(nldeb, "mysql:   col %d (%s) type %d:\n", j, mname, coltype);
93         switch(coltype) {
94           case FIELD_TYPE_TINY:
95           case FIELD_TYPE_SHORT:
96           case FIELD_TYPE_LONG:
97             if(!row[j]) piv = NULL;
98             else {
99               iv = strtol(row[j], NULL, 10);
100               piv = &iv;
101             }
102             noit_stats_set_metric(&current, mname, METRIC_INT32, piv);
103             break;
104           case FIELD_TYPE_INT24:
105           case FIELD_TYPE_LONGLONG:
106             if(!row[j]) plv = NULL;
107             else {
108               lv = strtoll(row[j], NULL, 10);
109               plv = &lv;
110             }
111             noit_stats_set_metric(&current, mname, METRIC_INT64, plv);
112             break;
113           case FIELD_TYPE_DECIMAL:
114           case FIELD_TYPE_FLOAT:
115           case FIELD_TYPE_DOUBLE:
116             if(!row[j]) pdv = NULL;
117             else {
118               dv = atof(row[j]);
119               pdv = &dv;
120             }
121             noit_stats_set_metric(&current, mname, METRIC_DOUBLE, pdv);
122             break;
123           default:
124             if(!row[j]) sv = NULL;
125             else sv = row[j];
126             noit_stats_set_metric(&current, mname, METRIC_GUESS, sv);
127             break;
128         }
129       }
130     }
131   }
132   noit_check_set_stats(self, check, &current);
133 }
134
135 #define FETCH_CONFIG_OR(key, str) do { \
136   if(!noit_hash_retrieve(check->config, #key, strlen(#key), (void **)&key)) \
137     key = str; \
138 } while(0)
139
140 #define AVAIL_BAIL(str) do { \
141   ci->timed_out = 0; \
142   ci->error = strdup(str); \
143   return 0; \
144 } while(0)
145
146 static char *
147 __noit__strndup(const char *src, int len) {
148   int slen;
149   char *dst;
150   for(slen = 0; slen < len; slen++)
151     if(src[slen] == '\0') break;
152   dst = malloc(slen + 1);
153   memcpy(dst, src, slen);
154   dst[slen] = '\0';
155   return dst;
156 }
157
158 void mysql_parse_dsn(const char *dsn, noit_hash_table *h) {
159   const char *a=dsn, *b=NULL, *c=NULL;
160   while (a && (NULL != (b = strchr(a, '=')))) {
161     char *key, *val=NULL;
162     key = __noit__strndup(a, b-a);
163     b++;
164     if (b) {
165       if (NULL != (c = strchr(b, ' '))) {
166         val = __noit__strndup(b, c-b);
167       } else {
168         val = strdup(b);
169       }
170     }
171     noit_hash_replace(h, key, key?strlen(key):0, val, free, free);
172     a = c;
173     if (a) a++;
174   }
175 }
176
177 static int mysql_drive_session(eventer_t e, int mask, void *closure,
178                                   struct timeval *now) {
179   const char *dsn, *sql;
180   char sql_buff[8192];
181   char dsn_buff[512];
182   mysql_check_info_t *ci = closure;
183   noit_check_t *check = ci->check;
184   noit_hash_table dsn_h = NOIT_HASH_EMPTY;
185   const char *host=NULL;
186   const char *user=NULL;
187   const char *password=NULL;
188   const char *dbname=NULL;
189   const char *port_s=NULL;
190   const char *socket=NULL;
191   u_int32_t port;
192   unsigned int timeout;
193
194   if(mask & (EVENTER_READ | EVENTER_WRITE)) {
195     /* this case is impossible from the eventer.  It is called as
196      * such on the synchronous completion of the event.
197      */
198     mysql_log_results(ci->self, ci->check);
199     mysql_cleanup(ci->self, ci->check);
200     check->flags &= ~NP_RUNNING;
201     return 0;
202   }
203   switch(mask) {
204     case EVENTER_ASYNCH_WORK:
205       FETCH_CONFIG_OR(dsn, "");
206       noit_check_interpolate(dsn_buff, sizeof(dsn_buff), dsn,
207                              &ci->attrs, check->config);
208
209       mysql_parse_dsn(dsn_buff, &dsn_h);
210       noit_hash_retrieve(&dsn_h, "host", strlen("host"), (void**)&host);
211       noit_hash_retrieve(&dsn_h, "user", strlen("user"), (void**)&user);
212       noit_hash_retrieve(&dsn_h, "password", strlen("password"), (void**)&password);
213       noit_hash_retrieve(&dsn_h, "dbname", strlen("dbname"), (void**)&dbname);
214       noit_hash_retrieve(&dsn_h, "port", strlen("port"), (void**)&port_s);
215       port = port_s ? strtol(port_s, NULL, 10) : 3306;
216       noit_hash_retrieve(&dsn_h, "socket", strlen("socket"), (void**)&socket);
217
218       ci->conn = mysql_init(NULL); /* allocate us a handle */
219       if(!ci->conn) AVAIL_BAIL("mysql_init failed");
220       timeout = check->timeout / 1000;
221       mysql_options(ci->conn, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&timeout);
222       if(!mysql_real_connect(ci->conn, host, user, password,
223                              dbname, port, socket, CLIENT_IGNORE_SIGPIPE)) {
224         noitL(noit_stderr, "error during mysql_real_connect: %s\n",
225           mysql_error(ci->conn));
226         AVAIL_BAIL(mysql_error(ci->conn));
227       }
228       if(mysql_ping(ci->conn))
229         AVAIL_BAIL(mysql_error(ci->conn));
230
231       FETCH_CONFIG_OR(sql, "");
232       noit_check_interpolate(sql_buff, sizeof(sql_buff), sql,
233                              &ci->attrs, check->config);
234       if (mysql_query(ci->conn, sql_buff))
235         AVAIL_BAIL(mysql_error(ci->conn));
236       ci->result = mysql_store_result(ci->conn);
237       if(!ci->result) AVAIL_BAIL("mysql_store_result failed");
238       ci->rv = mysql_num_rows(ci->result);
239       ci->timed_out = 0;
240       return 0;
241       break;
242     case EVENTER_ASYNCH_CLEANUP:
243       /* This sets us up for a completion call. */
244       e->mask = EVENTER_READ | EVENTER_WRITE;
245       break;
246     default:
247       abort();
248   }
249   return 0;
250 }
251
252 static int mysql_initiate(noit_module_t *self, noit_check_t *check) {
253   mysql_check_info_t *ci = check->closure;
254   struct timeval __now;
255
256   /* We cannot be running */
257   assert(!(check->flags & NP_RUNNING));
258   check->flags |= NP_RUNNING;
259
260   ci->self = self;
261   ci->check = check;
262
263   ci->timed_out = 1;
264   ci->rv = -1;
265   noit_check_make_attrs(check, &ci->attrs);
266   gettimeofday(&__now, NULL);
267   memcpy(&check->last_fire_time, &__now, sizeof(__now));
268
269   /* Register a handler for the worker */
270   noit_check_run_full_asynch(check, mysql_drive_session);
271   return 0;
272 }
273
274 static int mysql_initiate_check(noit_module_t *self, noit_check_t *check,
275                                    int once, noit_check_t *parent) {
276   if(!check->closure) check->closure = calloc(1, sizeof(mysql_check_info_t));
277   INITIATE_CHECK(mysql_initiate, self, check);
278   return 0;
279 }
280
281 static int mysql_onload(noit_image_t *self) {
282   nlerr = noit_log_stream_find("error/mysql");
283   nldeb = noit_log_stream_find("debug/mysql");
284   if(!nlerr) nlerr = noit_stderr;
285   if(!nldeb) nldeb = noit_debug;
286
287   eventer_name_callback("mysql/mysql_drive_session", mysql_drive_session);
288   return 0;
289 }
290
291 #include "mysql.xmlh"
292 noit_module_t mysql = {
293   {
294     NOIT_MODULE_MAGIC,
295     NOIT_MODULE_ABI_VERSION,
296     "mysql",
297     "MySQL Checker",
298     mysql_xml_description,
299     mysql_onload
300   },
301   NULL,
302   NULL,
303   mysql_initiate_check,
304   mysql_cleanup
305 };
306
Note: See TracBrowser for help on using the browser.