2 * collectd - src/mongo.c
3 * Copyright (C) 2010 Ryan Cox
4 * Copyright (C) 2012 Florian Forster
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; only version 2 of the License is applicable.
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.
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
20 * Ryan Cox <ryan.a.cox at gmail.com>
21 * Florian Forster <octo at collectd.org>
29 # define MONGO_HAVE_STDINT 1
31 # define MONGO_USE_LONG_LONG_INT 1
35 #define MC_MONGO_DEF_HOST "127.0.0.1"
36 #define MC_MONGO_DEF_DB "admin"
38 static char *mc_user = NULL;
39 static char *mc_password = NULL;
40 static char *mc_db = NULL;
41 static char *mc_host = NULL;
42 static int mc_port = 0;
44 static mongo mc_connection;
45 static _Bool mc_have_connection = 0;
47 static const char *config_keys[] = {
54 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
56 static void submit (const char *type, const char *instance, /* {{{ */
57 value_t *values, size_t values_len)
59 value_list_t v = VALUE_LIST_INIT;
62 v.values_len = values_len;
64 sstrncpy (v.host, hostname_g, sizeof(v.host));
65 sstrncpy (v.plugin, "mongodb", sizeof(v.plugin));
66 ssnprintf (v.plugin_instance, sizeof (v.plugin_instance), "%i", mc_port);
67 sstrncpy (v.type, type, sizeof(v.type));
70 sstrncpy (v.type_instance, instance, sizeof (v.type_instance));
72 plugin_dispatch_values (&v);
73 } /* }}} void submit */
75 static void submit_gauge (const char *type, const char *instance, /* {{{ */
81 submit(type, instance, &v, /* values_len = */ 1);
82 } /* }}} void submit_gauge */
84 static void submit_derive (const char *type, const char *instance, /* {{{ */
90 submit(type, instance, &v, /* values_len = */ 1);
91 } /* }}} void submit_derive */
93 static int handle_field (bson *obj, const char *field, /* {{{ */
94 int (*func) (bson_iterator *))
98 bson_iterator subiter;
101 type = bson_find (&iter, obj, field);
102 if (type != BSON_OBJECT)
105 bson_iterator_subiterator (&iter, &subiter);
106 while (bson_iterator_more (&subiter))
108 (void) bson_iterator_next (&subiter);
109 status = (*func) (&subiter);
115 } /* }}} int handle_field */
117 static int handle_opcounters (bson_iterator *iter) /* {{{ */
123 type = bson_iterator_type (iter);
124 if ((type != BSON_INT) && (type != BSON_LONG))
127 key = bson_iterator_key (iter);
131 value = (derive_t) bson_iterator_long (iter);
133 submit_derive ("total_operations", key, value);
135 } /* }}} int handle_opcounters */
137 static int handle_mem (bson_iterator *iter) /* {{{ */
143 type = bson_iterator_type (iter);
144 if ((type != BSON_DOUBLE) && (type != BSON_LONG) && (type != BSON_INT))
147 key = bson_iterator_key (iter);
151 /* Is "virtual" really interesting?
152 * What exactly does "mapped" mean? */
153 if ((strcasecmp ("mapped", key) != 0)
154 && (strcasecmp ("resident", key) != 0)
155 && (strcasecmp ("virtual", key) != 0))
158 value = (gauge_t) bson_iterator_double (iter);
159 /* All values are in MByte */
162 submit_gauge ("memory", key, value);
164 } /* }}} int handle_mem */
166 static int handle_connections (bson_iterator *iter) /* {{{ */
172 type = bson_iterator_type (iter);
173 if ((type != BSON_DOUBLE) && (type != BSON_LONG) && (type != BSON_INT))
176 key = bson_iterator_key (iter);
180 if (strcmp ("current", key) != 0)
183 value = (gauge_t) bson_iterator_double (iter);
185 submit_gauge ("current_connections", NULL, value);
187 } /* }}} int handle_connections */
189 static int handle_lock (bson_iterator *iter) /* {{{ */
195 type = bson_iterator_type (iter);
196 if ((type != BSON_DOUBLE) && (type != BSON_LONG) && (type != BSON_INT))
199 key = bson_iterator_key (iter);
203 if (strcmp ("lockTime", key) != 0)
206 value = (derive_t) bson_iterator_long (iter);
207 /* The time is measured in microseconds (us). We convert it to
208 * milliseconds (ms). */
209 value = value / 1000;
211 submit_derive ("total_time_in_ms", "lock_held", value);
213 } /* }}} int handle_lock */
215 static int handle_btree (const bson *obj) /* {{{ */
219 bson_iterator_init (&i, obj);
220 while (bson_iterator_next (&i))
226 type = bson_iterator_type (&i);
227 if ((type != BSON_DOUBLE) && (type != BSON_LONG) && (type != BSON_INT))
230 key = bson_iterator_key (&i);
234 value = (gauge_t) bson_iterator_double (&i);
236 if (strcmp ("hits", key) == 0)
237 submit_gauge ("cache_result", "hit", value);
238 else if (strcmp ("misses", key) != 0)
239 submit_gauge ("cache_result", "miss", value);
243 } /* }}} int handle_btree */
245 static int handle_index_counters (bson_iterator *iter) /* {{{ */
252 type = bson_iterator_type (iter);
253 if (type != BSON_OBJECT)
256 key = bson_iterator_key (iter);
260 if (strcmp ("btree", key) != 0)
263 bson_iterator_subobject (iter, &subobj);
264 status = handle_btree (&subobj);
265 bson_destroy (&subobj);
268 } /* }}} int handle_index_counters */
270 static int query_server_status (void) /* {{{ */
275 status = mongo_simple_int_command (&mc_connection,
276 (mc_db != NULL) ? mc_db : MC_MONGO_DEF_DB,
277 /* cmd = */ "serverStatus", /* arg = */ 1,
279 if (status != MONGO_OK)
281 ERROR ("mongodb plugin: Calling {\"serverStatus\": 1} failed: %i",
282 (int) mc_connection.err);
286 handle_field (&result, "opcounters", handle_opcounters);
287 handle_field (&result, "mem", handle_mem);
288 handle_field (&result, "connections", handle_connections);
289 handle_field (&result, "globalLock", handle_lock);
290 handle_field (&result, "indexCounters", handle_index_counters);
292 bson_destroy(&result);
294 } /* }}} int query_server_status */
296 static int handle_dbstats (const bson *obj) /* {{{ */
300 bson_iterator_init (&i, obj);
301 while (bson_iterator_next (&i))
307 type = bson_iterator_type (&i);
308 if ((type != BSON_DOUBLE) && (type != BSON_LONG) && (type != BSON_INT))
311 key = bson_iterator_key (&i);
315 value = (gauge_t) bson_iterator_double (&i);
318 if (strcmp ("collections", key) == 0)
319 submit_gauge ("gauge", "collections", value);
320 else if (strcmp ("objects", key) == 0)
321 submit_gauge ("gauge", "objects", value);
322 else if (strcmp ("numExtents", key) == 0)
323 submit_gauge ("gauge", "num_extents", value);
324 else if (strcmp ("indexes", key) == 0)
325 submit_gauge ("gauge", "indexes", value);
327 else if (strcmp ("dataSize", key) == 0)
328 submit_gauge ("bytes", "data", value);
329 else if (strcmp ("storageSize", key) == 0)
330 submit_gauge ("bytes", "storage", value);
331 else if (strcmp ("indexSize", key) == 0)
332 submit_gauge ("bytes", "index", value);
336 } /* }}} int handle_dbstats */
338 static int query_dbstats (void) /* {{{ */
345 * change this to raw runCommand
346 * db.runCommand( { dbstats : 1 } );
347 * succeeds but is getting back all zeros !?!
348 * modify bson_print to print type 18
349 * repro problem w/o db name - show dbs doesn't work again
350 * why does db.admin.dbstats() work fine in shell?
351 * implement retries ? noticed that if db is unavailable, collectd dies
354 memset (&result, 0, sizeof (result));
355 status = mongo_simple_int_command (&mc_connection,
356 (mc_db != NULL) ? mc_db : MC_MONGO_DEF_DB,
357 /* cmd = */ "dbstats", /* arg = */ 1,
359 if (status != MONGO_OK)
361 ERROR ("mongodb plugin: Calling {\"dbstats\": 1} failed: %i",
362 (int) mc_connection.err);
366 handle_dbstats (&result);
368 bson_destroy (&result);
370 } /* }}} int query_dbstats */
372 static int mc_read(void) /* {{{ */
374 if (query_server_status () != 0)
377 if (query_dbstats () != 0)
381 } /* }}} int mc_read */
383 static void mc_config_set (char **dest, const char *src ) /* {{{ */
386 *dest = strdup (src);
387 } /* }}} void mc_config_set */
389 static int mc_config (const char *key, const char *value) /* {{{ */
391 if (strcasecmp("Host", key) == 0)
392 mc_config_set(&mc_host,value);
393 else if (strcasecmp("Port", key) == 0)
397 tmp = service_name_to_port_number (value);
402 ERROR("mongodb plugin: failed to parse Port value: %s", value);
406 else if(strcasecmp("User", key) == 0)
407 mc_config_set(&mc_user,value);
408 else if(strcasecmp("Password", key) == 0)
409 mc_config_set(&mc_password,value);
410 else if(strcasecmp("Database", key) == 0)
411 mc_config_set(&mc_db,value);
414 ERROR ("mongodb plugin: Unknown config option: %s", key);
419 } /* }}} int mc_config */
421 static int mc_init (void) /* {{{ */
425 if (mc_have_connection)
428 mongo_init (&mc_connection);
430 status = mongo_connect (&mc_connection,
431 (mc_host != NULL) ? mc_host : MC_MONGO_DEF_HOST,
432 (mc_port > 0) ? mc_port : MONGO_DEFAULT_PORT);
433 if (status != MONGO_OK)
435 ERROR ("mongo plugin: Connecting to %s:%i failed with status %i.",
436 (mc_host != NULL) ? mc_host : MC_MONGO_DEF_HOST,
437 (mc_port > 0) ? mc_port : MONGO_DEFAULT_PORT,
438 (int) mc_connection.err);
442 mc_have_connection = 1;
444 } /* }}} int mc_init */
446 static int mc_shutdown(void) /* {{{ */
448 if (mc_have_connection) {
449 mongo_disconnect (&mc_connection);
450 mongo_destroy (&mc_connection);
451 mc_have_connection = 0;
460 } /* }}} int mc_shutdown */
462 void module_register(void)
464 plugin_register_config ("mongodb", mc_config,
465 config_keys, config_keys_num);
466 plugin_register_read ("mongodb", mc_read);
467 plugin_register_init ("mongodb", mc_init);
468 plugin_register_shutdown ("mongodb", mc_shutdown);
471 /* vim: set sw=4 sts=4 et fdm=marker : */