sammler/p_mysql.c

216 lines
5.8 KiB
C

/***************************************************************************
* Copyright (C) 10/2006 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "configfile.h"
#include "helper.h"
#include "list.h"
#include "plugins.h"
#include "p_mysql_helper.h"
#define DS_TRAFFIC 1
#define DS_COMMANDS 2
#define DS_QCACHE 3
#define DS_THREADS 4
struct server_entry {
struct list_head list;
void *mysql;
char name[0];
};
static LIST_HEAD(server_list);
static char *traffic_ds_def = {
"DS:bytes_received:COUNTER:90:0:U "
"DS:bytes_sent:COUNTER:90:0:U "
};
static char *commands_ds_def = {
"DS:com_delete:COUNTER:90:0:U "
"DS:com_insert:COUNTER:90:0:U "
"DS:com_select:COUNTER:90:0:U "
"DS:com_update:COUNTER:90:0:U "
"DS:connections:COUNTER:90:0:U "
"DS:questions:COUNTER:90:0:U "
};
static char *qcache_ds_def = {
"DS:qc_free_blocks:GAUGE:90:0:U "
"DS:qc_free_memory:GAUGE:90:0:U "
"DS:qc_hits:COUNTER:90:0:U "
"DS:qc_inserts:COUNTER:90:0:U "
"DS:qc_lowmem_prunes:COUNTER:90:0:U "
"DS:qc_not_cached:COUNTER:90:0:U "
"DS:qc_queries_in_cache:GAUGE:90:0:U "
"DS:qc_total_blocks:GAUGE:90:0:U "
};
static char *threads_ds_def = {
"DS:threads_cached:GAUGE:90:0:U "
"DS:threads_connected:GAUGE:90:0:U "
"DS:threads_created:COUNTER:90:0:U "
"DS:threads_running:GAUGE:90:0:U "
};
static char * get_ds(int ds_id)
{
switch (ds_id) {
case DS_TRAFFIC:
return traffic_ds_def;
case DS_COMMANDS:
return commands_ds_def;
case DS_QCACHE:
return qcache_ds_def;
case DS_THREADS:
return threads_ds_def;
default:
return NULL;
}
}
struct sammler_plugin plugin;
static int probe(void)
{
struct mysql_stats stats;
char filename[32];
int len;
memset(&stats, 0, sizeof(struct mysql_stats));
struct server_entry *entry;
list_for_each_entry(entry, &server_list, list) {
if (ping_connection(entry->mysql) != 0)
continue;
if (get_stats(entry->mysql, &stats) != 0)
continue;
len = snprintf(filename, sizeof(filename), "mysql-traffic-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_TRAFFIC, "%llu:%llu",
stats.bytes_received, stats.bytes_sent);
len = snprintf(filename, sizeof(filename), "mysql-commands-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_COMMANDS, "%llu:%llu:%llu:%llu:%llu:%llu",
stats.com_delete, stats.com_insert,
stats.com_select, stats.com_update,
stats.connections, stats.questions);
len = snprintf(filename, sizeof(filename), "mysql-qcache-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_QCACHE, "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
stats.qc_free_blocks, stats.qc_free_memory,
stats.qc_hits, stats.qc_inserts,
stats.qc_lowmem_prunes, stats.qc_not_cached,
stats.qc_queries_in_cache, stats.qc_total_blocks);
len = snprintf(filename, sizeof(filename), "mysql-threads-%s.rrd", entry->name);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, DS_THREADS, "%llu:%llu:%llu:%llu",
stats.threads_cached, stats.threads_connected,
stats.threads_created, stats.threads_running);
}
return 0;
}
static int init(void)
{
int retval = -1;
struct conf_section *section;
section = config_get_section("p_mysql");
if (section == NULL) {
log_print(LOG_ERROR, "p_mysql: no config section found");
return -1;
}
struct conf_tupel *tupel;
list_for_each_entry(tupel, &section->tupel, list) {
if (strcmp(tupel->option, "server"))
continue;
char *part[4];
int ret = strsplit(tupel->parameter, ",", part, 4);
if (ret != 4) {
log_print(LOG_ERROR, "p_mysql: parse error");
continue;
}
void *mysql = init_connection(part[1], part[2], part[3]);
if (mysql == NULL)
continue;
int len = strlen(part[0]);
struct server_entry *entry = malloc(sizeof(struct server_entry) + len +1);
if (entry == NULL) {
log_print(LOG_ERROR, "p_mysql: out of memory");
close_connection(mysql);
continue;
}
strcpy(entry->name, part[0]);
entry->mysql = mysql;
log_print(LOG_DEBUG, "p_mysql: added server '%s'", entry->name);
list_add_tail(&entry->list, &server_list);
retval = 0;
}
return retval;
}
static int fini(void)
{
struct server_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &server_list, list) {
close_connection(entry->mysql);
free(entry);
}
return 0;
}
struct sammler_plugin plugin = {
.name = "mysql",
.interval = 60,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};