/** * collectd - src/mysql.c * Copyright (C) 2006-2010 Florian octo Forster * Copyright (C) 2008 Mirko Buffoni * Copyright (C) 2009 Doug MacEachern * Copyright (C) 2009 Sebastian tokkee Harl * Copyright (C) 2009 Rodolphe QuiƩdeville * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; only version 2 of the License is applicable. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: * Florian octo Forster * Mirko Buffoni * Doug MacEachern * Sebastian tokkee Harl * Rodolphe QuiƩdeville **/ #include "collectd.h" #include "plugin.h" #include "utils/common/common.h" #ifdef HAVE_MYSQL_H #include #elif defined(HAVE_MYSQL_MYSQL_H) #include #endif struct mysql_database_s /* {{{ */ { char *instance; char *alias; char *host; char *user; char *pass; char *database; /* mysql_ssl_set params */ char *key; char *cert; char *ca; char *capath; char *cipher; char *socket; int port; int timeout; bool master_stats; bool slave_stats; bool innodb_stats; bool wsrep_stats; bool slave_notif; bool slave_io_running; bool slave_sql_running; MYSQL *con; bool is_connected; unsigned long mysql_version; }; typedef struct mysql_database_s mysql_database_t; /* }}} */ static int mysql_read(user_data_t *ud); static void mysql_database_free(void *arg) /* {{{ */ { mysql_database_t *db; DEBUG("mysql plugin: mysql_database_free (arg = %p);", arg); db = arg; if (db == NULL) return; if (db->con != NULL) mysql_close(db->con); sfree(db->alias); sfree(db->host); sfree(db->user); sfree(db->pass); sfree(db->socket); sfree(db->instance); sfree(db->database); sfree(db->key); sfree(db->cert); sfree(db->ca); sfree(db->capath); sfree(db->cipher); sfree(db); } /* }}} void mysql_database_free */ /* Configuration handling functions {{{ * * * * Host "localhost" * Port 22000 * ... * * */ static int mysql_config_database(oconfig_item_t *ci) /* {{{ */ { mysql_database_t *db; int status = 0; if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING("mysql plugin: The `Database' block " "needs exactly one string argument."); return -1; } db = calloc(1, sizeof(*db)); if (db == NULL) { ERROR("mysql plugin: calloc failed."); return -1; } /* initialize all the pointers */ db->alias = NULL; db->host = NULL; db->user = NULL; db->pass = NULL; db->database = NULL; db->key = NULL; db->cert = NULL; db->ca = NULL; db->capath = NULL; db->cipher = NULL; db->socket = NULL; db->con = NULL; db->timeout = 0; /* trigger a notification, if it's not running */ db->slave_io_running = true; db->slave_sql_running = true; status = cf_util_get_string(ci, &db->instance); if (status != 0) { sfree(db); return status; } assert(db->instance != NULL); /* Fill the `mysql_database_t' structure.. */ for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("Alias", child->key) == 0) status = cf_util_get_string(child, &db->alias); else if (strcasecmp("Host", child->key) == 0) status = cf_util_get_string(child, &db->host); else if (strcasecmp("User", child->key) == 0) status = cf_util_get_string(child, &db->user); else if (strcasecmp("Password", child->key) == 0) status = cf_util_get_string(child, &db->pass); else if (strcasecmp("Port", child->key) == 0) { status = cf_util_get_port_number(child); if (status > 0) { db->port = status; status = 0; } } else if (strcasecmp("Socket", child->key) == 0) status = cf_util_get_string(child, &db->socket); else if (strcasecmp("Database", child->key) == 0) status = cf_util_get_string(child, &db->database); else if (strcasecmp("SSLKey", child->key) == 0) status = cf_util_get_string(child, &db->key); else if (strcasecmp("SSLCert", child->key) == 0) status = cf_util_get_string(child, &db->cert); else if (strcasecmp("SSLCA", child->key) == 0) status = cf_util_get_string(child, &db->ca); else if (strcasecmp("SSLCAPath", child->key) == 0) status = cf_util_get_string(child, &db->capath); else if (strcasecmp("SSLCipher", child->key) == 0) status = cf_util_get_string(child, &db->cipher); else if (strcasecmp("ConnectTimeout", child->key) == 0) status = cf_util_get_int(child, &db->timeout); else if (strcasecmp("MasterStats", child->key) == 0) status = cf_util_get_boolean(child, &db->master_stats); else if (strcasecmp("SlaveStats", child->key) == 0) status = cf_util_get_boolean(child, &db->slave_stats); else if (strcasecmp("SlaveNotifications", child->key) == 0) status = cf_util_get_boolean(child, &db->slave_notif); else if (strcasecmp("InnodbStats", child->key) == 0) status = cf_util_get_boolean(child, &db->innodb_stats); else if (strcasecmp("WsrepStats", child->key) == 0) status = cf_util_get_boolean(child, &db->wsrep_stats); else { WARNING("mysql plugin: Option `%s' not allowed here.", child->key); status = -1; } if (status != 0) break; } /* If all went well, register this database for reading */ if (status == 0) { char cb_name[DATA_MAX_NAME_LEN]; DEBUG("mysql plugin: Registering new read callback: %s", (db->database != NULL) ? db->database : ""); if (db->instance != NULL) ssnprintf(cb_name, sizeof(cb_name), "mysql-%s", db->instance); else sstrncpy(cb_name, "mysql", sizeof(cb_name)); plugin_register_complex_read( /* group = */ NULL, cb_name, mysql_read, /* interval = */ 0, &(user_data_t){ .data = db, .free_func = mysql_database_free, }); } else { mysql_database_free(db); return -1; } return 0; } /* }}} int mysql_config_database */ static int mysql_config(oconfig_item_t *ci) /* {{{ */ { if (ci == NULL) return EINVAL; /* Fill the `mysql_database_t' structure.. */ for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("Database", child->key) == 0) mysql_config_database(child); else WARNING("mysql plugin: Option \"%s\" not allowed here.", child->key); } return 0; } /* }}} int mysql_config */ /* }}} End of configuration handling functions */ static MYSQL *getconnection(mysql_database_t *db) { const char *cipher; if (db->is_connected) { int status; status = mysql_ping(db->con); if (status == 0) return db->con; WARNING("mysql plugin: Lost connection to instance \"%s\": %s", db->instance, mysql_error(db->con)); } db->is_connected = false; /* Close the old connection before initializing a new one. */ if (db->con != NULL) { mysql_close(db->con); db->con = NULL; } db->con = mysql_init(NULL); if (db->con == NULL) { ERROR("mysql plugin: mysql_init failed: %s", mysql_error(db->con)); return NULL; } /* Configure TCP connect timeout (default: 0) */ db->con->options.connect_timeout = db->timeout; mysql_ssl_set(db->con, db->key, db->cert, db->ca, db->capath, db->cipher); if (mysql_real_connect(db->con, db->host, db->user, db->pass, db->database, db->port, db->socket, 0) == NULL) { ERROR("mysql plugin: Failed to connect to database %s " "at server %s: %s", (db->database != NULL) ? db->database : "", (db->host != NULL) ? db->host : "localhost", mysql_error(db->con)); return NULL; } cipher = mysql_get_ssl_cipher(db->con); db->mysql_version = mysql_get_server_version(db->con); INFO("mysql plugin: Successfully connected to database %s " "at server %s with cipher %s " "(server version: %s, protocol version: %d) ", (db->database != NULL) ? db->database : "", mysql_get_host_info(db->con), (cipher != NULL) ? cipher : "", mysql_get_server_info(db->con), mysql_get_proto_info(db->con)); db->is_connected = true; return db->con; } /* static MYSQL *getconnection (mysql_database_t *db) */ static void set_host(mysql_database_t *db, char *buf, size_t buflen) { if (db->alias) sstrncpy(buf, db->alias, buflen); else if ((db->host == NULL) || (strcmp("", db->host) == 0) || (strcmp("127.0.0.1", db->host) == 0) || (strcmp("localhost", db->host) == 0)) sstrncpy(buf, hostname_g, buflen); else sstrncpy(buf, db->host, buflen); } /* void set_host */ static void submit(const char *type, const char *type_instance, value_t *values, size_t values_len, mysql_database_t *db) { value_list_t vl = VALUE_LIST_INIT; vl.values = values; vl.values_len = values_len; set_host(db, vl.host, sizeof(vl.host)); sstrncpy(vl.plugin, "mysql", sizeof(vl.plugin)); /* Assured by "mysql_config_database" */ assert(db->instance != NULL); sstrncpy(vl.plugin_instance, db->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, type, sizeof(vl.type)); if (type_instance != NULL) sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); plugin_dispatch_values(&vl); } /* submit */ static void gauge_submit(const char *type, const char *type_instance, gauge_t value, mysql_database_t *db) { submit(type, type_instance, &(value_t){.gauge = value}, 1, db); } /* void gauge_submit */ static void derive_submit(const char *type, const char *type_instance, derive_t value, mysql_database_t *db) { submit(type, type_instance, &(value_t){.derive = value}, 1, db); } /* void derive_submit */ static void traffic_submit(derive_t rx, derive_t tx, mysql_database_t *db) { value_t values[] = { {.derive = rx}, {.derive = tx}, }; submit("mysql_octets", NULL, values, STATIC_ARRAY_SIZE(values), db); } /* void traffic_submit */ static MYSQL_RES *exec_query(MYSQL *con, const char *query) { MYSQL_RES *res; size_t query_len = strlen(query); if (mysql_real_query(con, query, query_len)) { ERROR("mysql plugin: Failed to execute query: %s", mysql_error(con)); INFO("mysql plugin: SQL query was: %s", query); return NULL; } res = mysql_store_result(con); if (res == NULL) { ERROR("mysql plugin: Failed to store query result: %s", mysql_error(con)); INFO("mysql plugin: SQL query was: %s", query); return NULL; } return res; } /* exec_query */ static int mysql_read_master_stats(mysql_database_t *db, MYSQL *con) { MYSQL_RES *res; MYSQL_ROW row; const char *query; int field_num; unsigned long long position; query = "SHOW MASTER STATUS"; res = exec_query(con, query); if (res == NULL) return -1; row = mysql_fetch_row(res); if (row == NULL) { ERROR("mysql plugin: Failed to get master statistics: " "`%s' did not return any rows.", query); mysql_free_result(res); return -1; } field_num = mysql_num_fields(res); if (field_num < 2) { ERROR("mysql plugin: Failed to get master statistics: " "`%s' returned less than two columns.", query); mysql_free_result(res); return -1; } position = atoll(row[1]); derive_submit("mysql_log_position", "master-bin", position, db); row = mysql_fetch_row(res); if (row != NULL) WARNING("mysql plugin: `%s' returned more than one row - " "ignoring further results.", query); mysql_free_result(res); return 0; } /* mysql_read_master_stats */ static int mysql_read_slave_stats(mysql_database_t *db, MYSQL *con) { MYSQL_RES *res; MYSQL_ROW row; const char *query; int field_num; /* WTF? libmysqlclient does not seem to provide any means to * translate a column name to a column index ... :-/ */ const int READ_MASTER_LOG_POS_IDX = 6; const int SLAVE_IO_RUNNING_IDX = 10; const int SLAVE_SQL_RUNNING_IDX = 11; const int EXEC_MASTER_LOG_POS_IDX = 21; const int SECONDS_BEHIND_MASTER_IDX = 32; query = "SHOW SLAVE STATUS"; res = exec_query(con, query); if (res == NULL) return -1; row = mysql_fetch_row(res); if (row == NULL) { ERROR("mysql plugin: Failed to get slave statistics: " "`%s' did not return any rows.", query); mysql_free_result(res); return -1; } field_num = mysql_num_fields(res); if (field_num < 33) { ERROR("mysql plugin: Failed to get slave statistics: " "`%s' returned less than 33 columns.", query); mysql_free_result(res); return -1; } if (db->slave_stats) { unsigned long long counter; double gauge; gauge_submit("bool", "slave-sql-running", (row[SLAVE_SQL_RUNNING_IDX] != NULL) && (strcasecmp(row[SLAVE_SQL_RUNNING_IDX], "yes") == 0), db); gauge_submit("bool", "slave-io-running", (row[SLAVE_IO_RUNNING_IDX] != NULL) && (strcasecmp(row[SLAVE_IO_RUNNING_IDX], "yes") == 0), db); counter = atoll(row[READ_MASTER_LOG_POS_IDX]); derive_submit("mysql_log_position", "slave-read", counter, db); counter = atoll(row[EXEC_MASTER_LOG_POS_IDX]); derive_submit("mysql_log_position", "slave-exec", counter, db); if (row[SECONDS_BEHIND_MASTER_IDX] != NULL) { gauge = atof(row[SECONDS_BEHIND_MASTER_IDX]); gauge_submit("time_offset", NULL, gauge, db); } } if (db->slave_notif) { notification_t n = {0, cdtime(), "", "", "mysql", "", "time_offset", "", NULL}; char *io, *sql; io = row[SLAVE_IO_RUNNING_IDX]; sql = row[SLAVE_SQL_RUNNING_IDX]; set_host(db, n.host, sizeof(n.host)); /* Assured by "mysql_config_database" */ assert(db->instance != NULL); sstrncpy(n.plugin_instance, db->instance, sizeof(n.plugin_instance)); if (((io == NULL) || (strcasecmp(io, "yes") != 0)) && (db->slave_io_running)) { n.severity = NOTIF_WARNING; ssnprintf(n.message, sizeof(n.message), "slave I/O thread not started or not connected to master"); plugin_dispatch_notification(&n); db->slave_io_running = false; } else if (((io != NULL) && (strcasecmp(io, "yes") == 0)) && (!db->slave_io_running)) { n.severity = NOTIF_OKAY; ssnprintf(n.message, sizeof(n.message), "slave I/O thread started and connected to master"); plugin_dispatch_notification(&n); db->slave_io_running = true; } if (((sql == NULL) || (strcasecmp(sql, "yes") != 0)) && (db->slave_sql_running)) { n.severity = NOTIF_WARNING; ssnprintf(n.message, sizeof(n.message), "slave SQL thread not started"); plugin_dispatch_notification(&n); db->slave_sql_running = false; } else if (((sql != NULL) && (strcasecmp(sql, "yes") == 0)) && (!db->slave_sql_running)) { n.severity = NOTIF_OKAY; ssnprintf(n.message, sizeof(n.message), "slave SQL thread started"); plugin_dispatch_notification(&n); db->slave_sql_running = true; } } row = mysql_fetch_row(res); if (row != NULL) WARNING("mysql plugin: `%s' returned more than one row - " "ignoring further results.", query); mysql_free_result(res); return 0; } /* mysql_read_slave_stats */ static int mysql_read_innodb_stats(mysql_database_t *db, MYSQL *con) { MYSQL_RES *res; MYSQL_ROW row; const char *query; struct { const char *key; const char *type; int ds_type; } metrics[] = { {"metadata_mem_pool_size", "bytes", DS_TYPE_GAUGE}, {"lock_deadlocks", "mysql_locks", DS_TYPE_DERIVE}, {"lock_timeouts", "mysql_locks", DS_TYPE_DERIVE}, {"lock_row_lock_current_waits", "mysql_locks", DS_TYPE_DERIVE}, {"buffer_pool_size", "bytes", DS_TYPE_GAUGE}, {"os_log_bytes_written", "operations", DS_TYPE_DERIVE}, {"os_log_pending_fsyncs", "operations", DS_TYPE_DERIVE}, {"os_log_pending_writes", "operations", DS_TYPE_DERIVE}, {"trx_rseg_history_len", "gauge", DS_TYPE_GAUGE}, {"adaptive_hash_searches", "operations", DS_TYPE_DERIVE}, {"file_num_open_files", "gauge", DS_TYPE_GAUGE}, {"ibuf_merges_insert", "operations", DS_TYPE_DERIVE}, {"ibuf_merges_delete_mark", "operations", DS_TYPE_DERIVE}, {"ibuf_merges_delete", "operations", DS_TYPE_DERIVE}, {"ibuf_merges_discard_insert", "operations", DS_TYPE_DERIVE}, {"ibuf_merges_discard_delete_mark", "operations", DS_TYPE_DERIVE}, {"ibuf_merges_discard_delete", "operations", DS_TYPE_DERIVE}, {"ibuf_merges_discard_merges", "operations", DS_TYPE_DERIVE}, {"ibuf_size", "bytes", DS_TYPE_GAUGE}, {"innodb_activity_count", "gauge", DS_TYPE_GAUGE}, {"innodb_rwlock_s_spin_waits", "operations", DS_TYPE_DERIVE}, {"innodb_rwlock_x_spin_waits", "operations", DS_TYPE_DERIVE}, {"innodb_rwlock_s_spin_rounds", "operations", DS_TYPE_DERIVE}, {"innodb_rwlock_x_spin_rounds", "operations", DS_TYPE_DERIVE}, {"innodb_rwlock_s_os_waits", "operations", DS_TYPE_DERIVE}, {"innodb_rwlock_x_os_waits", "operations", DS_TYPE_DERIVE}, {"dml_reads", "operations", DS_TYPE_DERIVE}, {"dml_inserts", "operations", DS_TYPE_DERIVE}, {"dml_deletes", "operations", DS_TYPE_DERIVE}, {"dml_updates", "operations", DS_TYPE_DERIVE}, {NULL, NULL, 0}}; if (db->mysql_version >= 100500) query = "SELECT name, count, type FROM information_schema.innodb_metrics " "WHERE enabled"; else query = "SELECT name, count, type FROM information_schema.innodb_metrics " "WHERE status = 'enabled'"; res = exec_query(con, query); if (res == NULL) return -1; while ((row = mysql_fetch_row(res))) { int i; char *key; unsigned long long val; key = row[0]; val = atoll(row[1]); for (i = 0; metrics[i].key != NULL && strcmp(metrics[i].key, key) != 0; i++) ; if (metrics[i].key == NULL) continue; switch (metrics[i].ds_type) { case DS_TYPE_COUNTER: derive_submit(metrics[i].type, key, (counter_t)val, db); break; case DS_TYPE_GAUGE: gauge_submit(metrics[i].type, key, (gauge_t)val, db); break; case DS_TYPE_DERIVE: derive_submit(metrics[i].type, key, (derive_t)val, db); break; } } mysql_free_result(res); return 0; } static int mysql_read_wsrep_stats(mysql_database_t *db, MYSQL *con) { MYSQL_RES *res; MYSQL_ROW row; const char *query; struct { const char *key; const char *type; int ds_type; } metrics[] = { {"wsrep_apply_oooe", "operations", DS_TYPE_DERIVE}, {"wsrep_apply_oool", "operations", DS_TYPE_DERIVE}, {"wsrep_causal_reads", "operations", DS_TYPE_DERIVE}, {"wsrep_commit_oooe", "operations", DS_TYPE_DERIVE}, {"wsrep_commit_oool", "operations", DS_TYPE_DERIVE}, {"wsrep_flow_control_recv", "operations", DS_TYPE_DERIVE}, {"wsrep_flow_control_sent", "operations", DS_TYPE_DERIVE}, {"wsrep_flow_control_paused", "operations", DS_TYPE_DERIVE}, {"wsrep_local_bf_aborts", "operations", DS_TYPE_DERIVE}, {"wsrep_local_cert_failures", "operations", DS_TYPE_DERIVE}, {"wsrep_local_commits", "operations", DS_TYPE_DERIVE}, {"wsrep_local_replays", "operations", DS_TYPE_DERIVE}, {"wsrep_received", "operations", DS_TYPE_DERIVE}, {"wsrep_replicated", "operations", DS_TYPE_DERIVE}, {"wsrep_received_bytes", "total_bytes", DS_TYPE_DERIVE}, {"wsrep_replicated_bytes", "total_bytes", DS_TYPE_DERIVE}, {"wsrep_apply_window", "gauge", DS_TYPE_GAUGE}, {"wsrep_commit_window", "gauge", DS_TYPE_GAUGE}, {"wsrep_cluster_size", "gauge", DS_TYPE_GAUGE}, {"wsrep_cert_deps_distance", "gauge", DS_TYPE_GAUGE}, {"wsrep_local_recv_queue", "queue_length", DS_TYPE_GAUGE}, {"wsrep_local_send_queue", "queue_length", DS_TYPE_GAUGE}, {NULL, NULL, 0} }; query = "SHOW GLOBAL STATUS LIKE 'wsrep_%'"; res = exec_query(con, query); if (res == NULL) return -1; row = mysql_fetch_row(res); if (row == NULL) { ERROR("mysql plugin: Failed to get wsrep statistics: " "`%s' did not return any rows.", query); mysql_free_result(res); return -1; } while ((row = mysql_fetch_row(res))) { int i; char *key; unsigned long long val; key = row[0]; val = atoll(row[1]); for (i = 0; metrics[i].key != NULL && strcmp(metrics[i].key, key) != 0; i++) ; if (metrics[i].key == NULL) continue; switch (metrics[i].ds_type) { case DS_TYPE_GAUGE: gauge_submit(metrics[i].type, key, (gauge_t)val, db); break; case DS_TYPE_DERIVE: derive_submit(metrics[i].type, key, (derive_t)val, db); break; } } mysql_free_result(res); return 0; } /* mysql_read_wsrep_stats */ static int mysql_read(user_data_t *ud) { mysql_database_t *db; MYSQL *con; MYSQL_RES *res; MYSQL_ROW row; const char *query; derive_t qcache_hits = 0; derive_t qcache_inserts = 0; derive_t qcache_not_cached = 0; derive_t qcache_lowmem_prunes = 0; gauge_t qcache_queries_in_cache = NAN; gauge_t threads_running = NAN; gauge_t threads_connected = NAN; gauge_t threads_cached = NAN; derive_t threads_created = 0; unsigned long long traffic_incoming = 0ULL; unsigned long long traffic_outgoing = 0ULL; if ((ud == NULL) || (ud->data == NULL)) { ERROR("mysql plugin: mysql_database_read: Invalid user data."); return -1; } db = (mysql_database_t *)ud->data; /* An error message will have been printed in this case */ if ((con = getconnection(db)) == NULL) return -1; query = "SHOW STATUS"; if (db->mysql_version >= 50002) query = "SHOW GLOBAL STATUS"; res = exec_query(con, query); if (res == NULL) return -1; while ((row = mysql_fetch_row(res))) { char *key; unsigned long long val; key = row[0]; val = atoll(row[1]); if (strncmp(key, "Com_", strlen("Com_")) == 0) { if (val == 0ULL) continue; /* Ignore `prepared statements' */ if (strncmp(key, "Com_stmt_", strlen("Com_stmt_")) != 0) derive_submit("mysql_commands", key + strlen("Com_"), val, db); } else if (strncmp(key, "Handler_", strlen("Handler_")) == 0) { if (val == 0ULL) continue; derive_submit("mysql_handler", key + strlen("Handler_"), val, db); } else if (strncmp(key, "Qcache_", strlen("Qcache_")) == 0) { if (strcmp(key, "Qcache_hits") == 0) qcache_hits = (derive_t)val; else if (strcmp(key, "Qcache_inserts") == 0) qcache_inserts = (derive_t)val; else if (strcmp(key, "Qcache_not_cached") == 0) qcache_not_cached = (derive_t)val; else if (strcmp(key, "Qcache_lowmem_prunes") == 0) qcache_lowmem_prunes = (derive_t)val; else if (strcmp(key, "Qcache_queries_in_cache") == 0) qcache_queries_in_cache = (gauge_t)val; } else if (strncmp(key, "Bytes_", strlen("Bytes_")) == 0) { if (strcmp(key, "Bytes_received") == 0) traffic_incoming += val; else if (strcmp(key, "Bytes_sent") == 0) traffic_outgoing += val; } else if (strncmp(key, "Threads_", strlen("Threads_")) == 0) { if (strcmp(key, "Threads_running") == 0) threads_running = (gauge_t)val; else if (strcmp(key, "Threads_connected") == 0) threads_connected = (gauge_t)val; else if (strcmp(key, "Threads_cached") == 0) threads_cached = (gauge_t)val; else if (strcmp(key, "Threads_created") == 0) threads_created = (derive_t)val; } else if (strncmp(key, "Table_locks_", strlen("Table_locks_")) == 0) { derive_submit("mysql_locks", key + strlen("Table_locks_"), val, db); } else if (db->innodb_stats && strncmp(key, "Innodb_", strlen("Innodb_")) == 0) { /* buffer pool */ if (strcmp(key, "Innodb_buffer_pool_pages_data") == 0) gauge_submit("mysql_bpool_pages", "data", val, db); else if (strcmp(key, "Innodb_buffer_pool_pages_dirty") == 0) gauge_submit("mysql_bpool_pages", "dirty", val, db); else if (strcmp(key, "Innodb_buffer_pool_pages_flushed") == 0) derive_submit("mysql_bpool_counters", "pages_flushed", val, db); else if (strcmp(key, "Innodb_buffer_pool_pages_free") == 0) gauge_submit("mysql_bpool_pages", "free", val, db); else if (strcmp(key, "Innodb_buffer_pool_pages_misc") == 0) gauge_submit("mysql_bpool_pages", "misc", val, db); else if (strcmp(key, "Innodb_buffer_pool_pages_total") == 0) gauge_submit("mysql_bpool_pages", "total", val, db); else if (strcmp(key, "Innodb_buffer_pool_read_ahead_rnd") == 0) derive_submit("mysql_bpool_counters", "read_ahead_rnd", val, db); else if (strcmp(key, "Innodb_buffer_pool_read_ahead") == 0) derive_submit("mysql_bpool_counters", "read_ahead", val, db); else if (strcmp(key, "Innodb_buffer_pool_read_ahead_evicted") == 0) derive_submit("mysql_bpool_counters", "read_ahead_evicted", val, db); else if (strcmp(key, "Innodb_buffer_pool_read_requests") == 0) derive_submit("mysql_bpool_counters", "read_requests", val, db); else if (strcmp(key, "Innodb_buffer_pool_reads") == 0) derive_submit("mysql_bpool_counters", "reads", val, db); else if (strcmp(key, "Innodb_buffer_pool_wait_free") == 0) derive_submit("mysql_bpool_counters", "wait_free", val, db); else if (strcmp(key, "Innodb_buffer_pool_write_requests") == 0) derive_submit("mysql_bpool_counters", "write_requests", val, db); else if (strcmp(key, "Innodb_buffer_pool_bytes_data") == 0) gauge_submit("mysql_bpool_bytes", "data", val, db); else if (strcmp(key, "Innodb_buffer_pool_bytes_dirty") == 0) gauge_submit("mysql_bpool_bytes", "dirty", val, db); /* data */ if (strcmp(key, "Innodb_data_fsyncs") == 0) derive_submit("mysql_innodb_data", "fsyncs", val, db); else if (strcmp(key, "Innodb_data_read") == 0) derive_submit("mysql_innodb_data", "read", val, db); else if (strcmp(key, "Innodb_data_reads") == 0) derive_submit("mysql_innodb_data", "reads", val, db); else if (strcmp(key, "Innodb_data_writes") == 0) derive_submit("mysql_innodb_data", "writes", val, db); else if (strcmp(key, "Innodb_data_written") == 0) derive_submit("mysql_innodb_data", "written", val, db); /* double write */ else if (strcmp(key, "Innodb_dblwr_writes") == 0) derive_submit("mysql_innodb_dblwr", "writes", val, db); else if (strcmp(key, "Innodb_dblwr_pages_written") == 0) derive_submit("mysql_innodb_dblwr", "written", val, db); else if (strcmp(key, "Innodb_dblwr_page_size") == 0) gauge_submit("mysql_innodb_dblwr", "page_size", val, db); /* log */ else if (strcmp(key, "Innodb_log_waits") == 0) derive_submit("mysql_innodb_log", "waits", val, db); else if (strcmp(key, "Innodb_log_write_requests") == 0) derive_submit("mysql_innodb_log", "write_requests", val, db); else if (strcmp(key, "Innodb_log_writes") == 0) derive_submit("mysql_innodb_log", "writes", val, db); else if (strcmp(key, "Innodb_os_log_fsyncs") == 0) derive_submit("mysql_innodb_log", "fsyncs", val, db); else if (strcmp(key, "Innodb_os_log_written") == 0) derive_submit("mysql_innodb_log", "written", val, db); /* pages */ else if (strcmp(key, "Innodb_pages_created") == 0) derive_submit("mysql_innodb_pages", "created", val, db); else if (strcmp(key, "Innodb_pages_read") == 0) derive_submit("mysql_innodb_pages", "read", val, db); else if (strcmp(key, "Innodb_pages_written") == 0) derive_submit("mysql_innodb_pages", "written", val, db); /* row lock */ else if (strcmp(key, "Innodb_row_lock_time") == 0) derive_submit("mysql_innodb_row_lock", "time", val, db); else if (strcmp(key, "Innodb_row_lock_waits") == 0) derive_submit("mysql_innodb_row_lock", "waits", val, db); /* rows */ else if (strcmp(key, "Innodb_rows_deleted") == 0) derive_submit("mysql_innodb_rows", "deleted", val, db); else if (strcmp(key, "Innodb_rows_inserted") == 0) derive_submit("mysql_innodb_rows", "inserted", val, db); else if (strcmp(key, "Innodb_rows_read") == 0) derive_submit("mysql_innodb_rows", "read", val, db); else if (strcmp(key, "Innodb_rows_updated") == 0) derive_submit("mysql_innodb_rows", "updated", val, db); } else if (strncmp(key, "Select_", strlen("Select_")) == 0) { derive_submit("mysql_select", key + strlen("Select_"), val, db); } else if (strncmp(key, "Sort_", strlen("Sort_")) == 0) { if (strcmp(key, "Sort_merge_passes") == 0) derive_submit("mysql_sort_merge_passes", NULL, val, db); else if (strcmp(key, "Sort_rows") == 0) derive_submit("mysql_sort_rows", NULL, val, db); else if (strcmp(key, "Sort_range") == 0) derive_submit("mysql_sort", "range", val, db); else if (strcmp(key, "Sort_scan") == 0) derive_submit("mysql_sort", "scan", val, db); } else if (strncmp(key, "Slow_queries", strlen("Slow_queries")) == 0) { derive_submit("mysql_slow_queries", NULL, val, db); } else if (strcmp(key, "Uptime") == 0) { gauge_submit("uptime", NULL, val, db); } } mysql_free_result(res); res = NULL; if ((qcache_hits != 0) || (qcache_inserts != 0) || (qcache_not_cached != 0) || (qcache_lowmem_prunes != 0)) { derive_submit("cache_result", "qcache-hits", qcache_hits, db); derive_submit("cache_result", "qcache-inserts", qcache_inserts, db); derive_submit("cache_result", "qcache-not_cached", qcache_not_cached, db); derive_submit("cache_result", "qcache-prunes", qcache_lowmem_prunes, db); gauge_submit("cache_size", "qcache", qcache_queries_in_cache, db); } if (threads_created != 0) { gauge_submit("threads", "running", threads_running, db); gauge_submit("threads", "connected", threads_connected, db); gauge_submit("threads", "cached", threads_cached, db); derive_submit("total_threads", "created", threads_created, db); } traffic_submit(traffic_incoming, traffic_outgoing, db); if (db->mysql_version >= 50600 && db->innodb_stats) mysql_read_innodb_stats(db, con); if (db->master_stats) mysql_read_master_stats(db, con); if ((db->slave_stats) || (db->slave_notif)) mysql_read_slave_stats(db, con); if (db->wsrep_stats) mysql_read_wsrep_stats(db, con); return 0; } /* int mysql_read */ void module_register(void) { plugin_register_complex_config("mysql", mysql_config); } /* void module_register */