diff --git a/Makefile b/Makefile index 9b4db8f..df8b73d 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,8 @@ WITH_RRD = yes WITH_MYSQL = yes +WITH_CURL = yes + # ############################ SAMMLER_SRC := sammler.c configfile.c helper.c logging.c network.c plugins.c @@ -24,6 +26,10 @@ ifeq ("$(WITH_MYSQL)", "yes") PLUGIN_SRC += p_mysql.c endif +ifeq ("$(WITH_CURL)", "yes") + PLUGIN_SRC += p_apache.c +endif + # ############################ all: sammler $(PLUGIN_SRC:%.c=%.so) @@ -40,6 +46,9 @@ sammler: $(SAMMLER_SRC:%.c=%.o) %_sh.o: %.c $(CC) $(CFLAGS) -fPIC -o $@ -c $< +p_apache.so: p_apache_sh.o + $(LD) -shared -lcurl -o $@ $^ + p_mysql.so: p_mysql_sh.o p_mysql_helper_sh.o $(LD) -shared -lmysqlclient -o $@ $^ diff --git a/helper.c b/helper.c index e64dec8..384411e 100644 --- a/helper.c +++ b/helper.c @@ -23,7 +23,7 @@ int strsplit(char *string, char *delim, char **fields, int size) { - size_t i = 0; + int i = 0; char *tmp, *ptr = string; while ((fields[i] = strtok_r(ptr, delim, &tmp)) != NULL) { diff --git a/p_apache.c b/p_apache.c new file mode 100644 index 0000000..6167359 --- /dev/null +++ b/p_apache.c @@ -0,0 +1,234 @@ +/*************************************************************************** + * 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 +#include +#include + +#include + +#include "configfile.h" +#include "helper.h" +#include "list.h" +#include "plugins.h" + +#define BUFSIZE 8192 + +struct server_entry { + struct list_head list; + CURL *handle; + char *name; +}; + +static LIST_HEAD(server_list); + +static char *ds_def = { + "DS:total_accesses:COUNTER:90:0:U " + "DS:total_kbytes:COUNTER:90:0:U " + "DS:busy_workers:GAUGE:90:0:U " + "DS:idle_workers:GAUGE:90:0:U " +}; + +struct stats { + uint32_t total_accesses; + uint32_t total_kbytes; + uint32_t busy_workers; + uint32_t idle_workers; +}; + +struct sammler_plugin plugin; + +static char *rx_buf; +static int rx_pos; + +static char * get_ds(int ds_id) +{ + return ds_def; +} + +static size_t curl_callback(void *buffer, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + + // discard data + if (rx_pos + realsize >= BUFSIZE) + return realsize; + + memcpy(rx_buf + rx_pos, buffer, realsize); + + rx_pos += realsize; + return realsize; +} + +static int probe(void) +{ + struct server_entry *entry; + list_for_each_entry(entry, &server_list, list) { + rx_pos = 0; + curl_easy_perform(entry->handle); + + struct stats stats; + memset(&stats, 0, sizeof(stats)); + + char *line, *tmp = rx_buf, *tmp2; + while ((line = strtok_r(tmp, "\r\n", &tmp2))) { + char *part[2]; + strsplit(line, ":", part, 2); + + if (!strcmp(part[0], "Total Accesses")) + stats.total_accesses = atoll(part[1]); + + else if (!strcmp(part[0], "Total kBytes")) + stats.total_kbytes = atoll(part[1]); + + else if (!strcmp(part[0], "BusyWorkers")) + stats.busy_workers = atoll(part[1]); + + else if (!strcmp(part[0], "IdleWorkers")) + stats.idle_workers = atoll(part[1]); + + tmp = NULL; + } + + char filename[32]; + int len = snprintf(filename, sizeof(filename), "apache-%s.rrd", entry->name); + if (len < 0 || len >= sizeof(filename)) + continue; + + probe_submit(&plugin, filename, 0, "%llu:%llu:%llu:%llu", + stats.total_accesses, stats.total_kbytes, + stats.busy_workers, stats.idle_workers); + } + return 0; +} + +static int init(void) +{ + rx_buf = malloc(BUFSIZE); + if (rx_buf == NULL) { + log_print(LOG_ERROR, "p_apache: out of memory"); + return -1; + } + + struct conf_section *section; + section = config_get_section("p_apache"); + if (section == NULL) { + log_print(LOG_ERROR, "p_apache: no config section found"); + free(rx_buf); + return -1; + } + + int retval = -1; + struct conf_tupel *tupel; + list_for_each_entry(tupel, §ion->tupel, list) { + if (strcmp(tupel->option, "server")) + continue; + + char *part[4]; + int ret = strsplit(tupel->parameter, ",", part, 4); + if (ret < 2) { + log_print(LOG_ERROR, "p_apache: parse error (1)"); + continue; + } + + struct server_entry *entry = malloc(sizeof(struct server_entry)); + if (entry == NULL) { + log_print(LOG_ERROR, "p_apache: out of memory"); + continue; + } + + // reference config mem + entry->name = part[0]; + + entry->handle = curl_easy_init(); + if (entry->handle == NULL) { + free(entry); + continue; + } + + ret = curl_easy_setopt(entry->handle, CURLOPT_URL, part[1]); + if (ret != 0) { + log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret)); + curl_easy_cleanup(entry->handle); + free(entry); + continue; + } + + if (part[2] != NULL && part[3] != NULL) { + *(part[3] -1) = ':'; + + log_print(LOG_INFO, "p_apache: auth: '%s'", part[2]); + + ret = curl_easy_setopt(entry->handle, CURLOPT_USERPWD, part[2]); + if (ret != 0) { + log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret)); + curl_easy_cleanup(entry->handle); + free(entry); + continue; + } + } + + ret = curl_easy_setopt(entry->handle, CURLOPT_WRITEFUNCTION, &curl_callback); + if (ret != 0) { + log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret)); + curl_easy_cleanup(entry->handle); + free(entry); + continue; + } + + ret = curl_easy_setopt(entry->handle, CURLOPT_WRITEDATA, entry); + if (ret != 0) { + log_print(LOG_ERROR, "p_apache: %s", curl_easy_strerror(ret)); + curl_easy_cleanup(entry->handle); + free(entry); + continue; + } + + log_print(LOG_INFO, "p_apache: added server '%s'", entry->name); + list_add_tail(&entry->list, &server_list); + + retval = 0; + } + + if (retval == -1) + free(rx_buf); + + return retval; +} + +static int fini(void) +{ + struct server_entry *entry, *tmp; + list_for_each_entry_safe(entry, tmp, &server_list, list) { + curl_easy_cleanup(entry->handle); + free(entry); + } + + free(rx_buf); + return 0; +} + +struct sammler_plugin plugin = { + .name = "apache", + .interval = 10, + .init = &init, + .fini = &fini, + .probe = &probe, + .get_ds = &get_ds, +}; diff --git a/sammler.conf b/sammler.conf index 6ec8bc7..d9afcc2 100644 --- a/sammler.conf +++ b/sammler.conf @@ -20,7 +20,8 @@ plugin p_mount.so #plugin p_ctstat.so #plugin p_rtstat.so plugin p_random.so -#plugin p_mysql.so +plugin p_mysql.so +plugin p_apache.so # 1h(10s), 12h(1min), 48h(2min), 14d(15min), 4w(60min), 2y(12h) rra RRA:MIN:0.1:1:360 RRA:AVERAGE:0.1:1:360 RRA:MAX:0.1:1:360 @@ -31,4 +32,7 @@ rra RRA:MIN:0.1:360:1440 RRA:AVERAGE:0.1:360:1440 RRA:MAX:0.1:360:1440 rra RRA:MIN:0.1:4320:1440 RRA:AVERAGE:0.1:4320:1440 RRA:MAX:0.1:4320:1440 [p_mysql] -server name:host:user:pass +#server name,host,user,password + +[p_apache] +#server name,url,user,password