/*************************************************************************** * 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 { uint64_t total_accesses; uint64_t total_kbytes; uint64_t busy_workers; uint64_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") || !strcmp(part[0], "BusyServers")) stats.busy_workers = atoll(part[1]); else if (!strcmp(part[0], "IdleWorkers") || !strcmp(part[0], "IdleServers")) 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; } 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); } return 0; } 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 = 60, .init = &init, .fini = &fini, .probe = &probe, .get_ds = &get_ds, };