Index: collectd-20071004/configure.in =================================================================== --- collectd-20071004.orig/configure.in +++ collectd-20071004/configure.in @@ -1821,6 +1821,7 @@ AC_PLUGIN([mbmon], [yes], AC_PLUGIN([memory], [$plugin_memory], [Memory usage]) AC_PLUGIN([multimeter], [$plugin_multimeter], [Read multimeter values]) AC_PLUGIN([mysql], [$with_libmysql], [MySQL statistics]) +AC_PLUGIN([nginx], [$with_libcurl], [nginx statistics]) AC_PLUGIN([netlink], [$with_libnetlink], [Enhanced Linux network statistics]) AC_PLUGIN([network], [yes], [Network communication plugin]) AC_PLUGIN([nfs], [$plugin_nfs], [NFS statistics]) @@ -1937,6 +1938,7 @@ Configuration: memory . . . . . . $enable_memory multimeter . . . . $enable_multimeter mysql . . . . . . . $enable_mysql + nginx . . . . . . . $enable_nginx netlink . . . . . . $enable_netlink network . . . . . . $enable_network nfs . . . . . . . . $enable_nfs Index: collectd-20071004/src/Makefile.am =================================================================== --- collectd-20071004.orig/src/Makefile.am +++ collectd-20071004/src/Makefile.am @@ -349,6 +349,20 @@ endif collectd_DEPENDENCIES += mysql.la endif +if BUILD_PLUGIN_NGINX +pkglib_LTLIBRARIES += nginx.la +nginx_la_SOURCES = nginx.c +nginx_la_LDFLAGS = -module -avoid-version +nginx_la_CFLAGS = +nginx_la_LIBADD = +collectd_LDADD += "-dlopen" nginx.la +if BUILD_WITH_LIBCURL +nginx_la_CFLAGS += $(BUILD_WITH_LIBCURL_CFLAGS) +nginx_la_LIBADD += $(BUILD_WITH_LIBCURL_LIBS) +endif +collectd_DEPENDENCIES += nginx.la +endif + if BUILD_PLUGIN_NETLINK pkglib_LTLIBRARIES += netlink.la netlink_la_SOURCES = netlink.c Index: collectd-20071004/src/nginx.c =================================================================== --- /dev/null +++ collectd-20071004/src/nginx.c @@ -0,0 +1,358 @@ +/** + * collectd - src/nginx.c + * Copyright (C) 2007 Antony Dovgal, heavily based on apache.c + * + * 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: + * Antony Dovgal + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" +#include "configfile.h" + +#include + +static char *url = NULL; +static char *user = NULL; +static char *pass = NULL; +static char *cacert = NULL; + +static CURL *curl = NULL; + +#define NGBUFFER_SIZE 16384 +static char nginx_buffer[NGBUFFER_SIZE]; +static int nginx_buffer_len = 0; +static char nginx_curl_error[CURL_ERROR_SIZE]; + +static const char *config_keys[] = /* {{{ */ +{ + "URL", + "User", + "Password", + "CACert", + NULL +}; +/* }}} */ +static int config_keys_num = 4; + +static size_t nginx_curl_callback (void *buf, size_t size, size_t nmemb, void *stream) /* {{{ */ +{ + size_t len = size * nmemb; + + if ((nginx_buffer_len + len) >= NGBUFFER_SIZE) { + len = (NGBUFFER_SIZE - 1) - nginx_buffer_len; + } + + if (len <= 0) { + return len; + } + + memcpy (nginx_buffer + nginx_buffer_len, (char *) buf, len); + nginx_buffer_len += len; + nginx_buffer[nginx_buffer_len] = '\0'; + + return len; +} +/* }}} */ + +static int nginx_config_set (char **var, const char *value) /* {{{ */ +{ + if (*var != NULL) { + free (*var); + *var = NULL; + } + + if ((*var = strdup (value)) == NULL) { + return 1; + } + return 0; +} +/* }}} */ + +static int nginx_config (const char *key, const char *value) /* {{{ */ +{ + if (strcasecmp (key, "url") == 0) { + return (nginx_config_set (&url, value)); + } else if (strcasecmp (key, "user") == 0) { + return (nginx_config_set (&user, value)); + } else if (strcasecmp (key, "password") == 0) { + return (nginx_config_set (&pass, value)); + } else if (strcasecmp (key, "cacert") == 0) { + return (nginx_config_set (&cacert, value)); + } + return -1; +} +/* }}} */ + +static int nginx_init (void) /* {{{ */ +{ + static char credentials[1024]; + + DEBUG("nginx: initializing"); + + if (curl != NULL) { + curl_easy_cleanup (curl); + } + + if ((curl = curl_easy_init ()) == NULL) { + ERROR ("nginx: `curl_easy_init' failed."); + return -1; + } + + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, nginx_curl_callback); + curl_easy_setopt (curl, CURLOPT_USERAGENT, PACKAGE_NAME"/"PACKAGE_VERSION); + curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, nginx_curl_error); + + if (user != NULL) { + if (snprintf (credentials, 1024, "%s:%s", user, pass == NULL ? "" : pass) >= 1024) { + ERROR ("nginx: Credentials would have been truncated."); + return -1; + } + + curl_easy_setopt (curl, CURLOPT_USERPWD, credentials); + } + + if (url != NULL) { + curl_easy_setopt (curl, CURLOPT_URL, url); + } + + if (cacert != NULL) { + curl_easy_setopt (curl, CURLOPT_CAINFO, cacert); + } + + DEBUG("nginx: initialized successfully"); + return 0; +} /* int init */ +/* }}} */ + +static void nginx_submit_counter (const char *type, const char *type_instance, unsigned long long value) /* {{{ */ +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + DEBUG ("type = %s; type_instance = %s; value = %llu;", type, type_instance, value); + + values[0].counter = value; + + vl.values = values; + vl.values_len = 1; + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "nginx"); + strcpy (vl.plugin_instance, ""); + strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + + plugin_dispatch_values (type, &vl); +} +/* }}} */ + +static void nginx_submit_gauge (const char *type, const char *type_instance, double value) /* {{{ */ +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + DEBUG ("type = %s; type_instance = %s; value = %lf;", type, type_instance, value); + + values[0].gauge = value; + + vl.values = values; + vl.values_len = 1; + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "nginx"); + strcpy (vl.plugin_instance, ""); + + if (type_instance != NULL) { + strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + } + + plugin_dispatch_values (type, &vl); +} +/* }}} */ + +static void nginx_submit_requests (unsigned long long accepted, unsigned long long handled, unsigned long long requests) /* {{{ */ +{ + value_t values[3]; + value_list_t vl = VALUE_LIST_INIT; + + DEBUG("nginx: nginx_requests accepted = %lld, handled = %lld, requests = %lld", accepted, handled, requests); + + values[0].counter = accepted; + values[1].counter = handled; + values[2].counter = requests; + + vl.values = values; + vl.values_len = 3; + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "nginx"); + + plugin_dispatch_values ("nginx_requests", &vl); +} +/* }}} */ + +static void nginx_submit_connections (double active) /* {{{ */ +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + DEBUG("nginx: nginx_connections active = %lf", active); + + values[0].gauge = active; + + vl.values = values; + vl.values_len = 1; + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "nginx"); + + plugin_dispatch_values ("nginx_connections", &vl); +} +/* }}} */ + +static void nginx_submit_scoreboard (double reading, double writing, double waiting) /* {{{ */ +{ + value_t values[3]; + value_list_t vl = VALUE_LIST_INIT; + + DEBUG("nginx: nginx_scoreboard reading= %lf, writing = %lf, waiting = %lf", reading, writing, waiting); + + values[0].gauge = reading; + values[1].gauge = writing; + values[2].gauge = waiting; + + vl.values = values; + vl.values_len = 3; + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "nginx"); + + plugin_dispatch_values ("nginx_scoreboard", &vl); +} +/* }}} */ + +static int nginx_read (void) /* {{{ */ +{ + int i; + + char *ptr; + char *saveptr; + char *lines[5]; + int lines_num = 0; + + char *fields[6]; + int fields_num; + + unsigned long long active, accepted, handled, requests, reading, writing, waiting; + + DEBUG("nginx: executing nginx_read"); + + if (curl == NULL) { + return -1; + } + if (url == NULL) { + return -1; + } + + nginx_buffer_len = 0; + if (curl_easy_perform (curl) != 0) { + ERROR ("nginx: curl_easy_perform failed: %s", nginx_curl_error); + return -1; + } + + ptr = nginx_buffer; + saveptr = NULL; + while ((lines[lines_num] = strtok_r (ptr, "\n\r", &saveptr)) != NULL) { + ptr = NULL; + lines_num++; + + if (lines_num >= 5) + break; + } + +/* here is how nginx stats look at the moment */ +/* +Active connections: %d +server accepts handled requests + %d %d %d +Reading: %d Writing: %d Waiting: %d +*/ + + if (lines_num != 4) { + ERROR ("nginx: unknown status page format, expected 4 lines, got %d lines instead", lines_num); + return -1; + } + + fields_num = strsplit(lines[0], fields, 6); + if (fields_num != 3) { + ERROR ("nginx: invalid data - expected 3 columns on the 1st line, got %d columns instead", fields_num); + return -1; + } + + active = atoll(fields[2]); + + fields_num = strsplit(lines[2], fields, 6); + if (fields_num != 3) { + ERROR ("nginx: invalid data - expected 3 columns on the 3nd line, got %d columns instead", fields_num); + return -1; + } + + accepted = atoll(fields[0]); + handled = atoll(fields[1]); + requests = atoll(fields[2]); + + fields_num = strsplit(lines[3], fields, 6); + if (fields_num != 6) { + ERROR ("nginx: invalid data - expected 6 columns on the 4nd line, got %d columns instead", fields_num); + return -1; + } + + reading = atoll(fields[1]); + writing = atoll(fields[3]); + waiting = atoll(fields[5]); + + /* send the data */ + + nginx_submit_connections (active); + nginx_submit_requests (accepted, handled, requests); + nginx_submit_scoreboard (reading, writing, waiting); + + nginx_buffer_len = 0; + + DEBUG("nginx: successfully executed nginx_read"); + + return 0; +} +/* }}} */ + +void module_register (void) /* {{{ */ +{ + plugin_register_config ("nginx", nginx_config, config_keys, config_keys_num); + plugin_register_init ("nginx", nginx_init); + plugin_register_read ("nginx", nginx_read); +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ + Index: collectd-20071004/src/types.db =================================================================== --- collectd-20071004.orig/src/types.db +++ collectd-20071004/src/types.db @@ -70,3 +70,6 @@ vs_memory value:GAUGE:0:922337203685477 signal_quality value:GAUGE:0:U signal_power value:GAUGE:U:0 signal_noise value:GAUGE:U:0 +nginx_connections active:GAUGE:0:U +nginx_requests accepted:COUNTER:0:U, handled:COUNTER:0:U, requests:COUNTER:0:U +nginx_scoreboard reading:GAUGE:0:U, writing:GAUGE:0:U, waiting:GAUGE:0:U