NFS Procedures: Which NFS command were called how often. Only NFSv2 and
NFSv3 right now.
+ - nginx
+ Collects statistics from `nginx' (speak: engine X), a HTTP and mail
+ server/proxy.
+
- ntp
NTP daemon statistics: Local clock drift, offset to peers, etc.
then
plugin_cpu="yes"
plugin_memory="yes"
+ plugin_tcpconns="yes"
fi
if test "x$have_statfs" = "xyes"
AC_PLUGIN([netlink], [$with_libnetlink], [Enhanced Linux network statistics])
AC_PLUGIN([network], [yes], [Network communication plugin])
AC_PLUGIN([nfs], [$plugin_nfs], [NFS statistics])
+AC_PLUGIN([nginx], [$with_libcurl], [nginx statistics])
AC_PLUGIN([ntpd], [yes], [NTPd statistics])
AC_PLUGIN([nut], [$with_libupsclient], [Network UPS tools statistics])
AC_PLUGIN([perl], [$with_libperl], [Embed a Perl interpreter])
netlink . . . . . . $enable_netlink
network . . . . . . $enable_network
nfs . . . . . . . . $enable_nfs
+ nginx . . . . . . . $enable_nginx
ntpd . . . . . . . $enable_ntpd
nut . . . . . . . . $enable_nut
perl . . . . . . . $enable_perl
collectd_DEPENDENCIES += nfs.la
endif
+if BUILD_PLUGIN_NGINX
+pkglib_LTLIBRARIES += nginx.la
+nginx_la_SOURCES = nginx.c
+nginx_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBCURL
+nginx_la_LDFLAGS += $(BUILD_WITH_LIBCURL_LIBS)
+endif
+collectd_LDADD += "-dlopen" nginx.la
+collectd_DEPENDENCIES += nginx.la
+endif
+
if BUILD_PLUGIN_NTPD
pkglib_LTLIBRARIES += ntpd.la
ntpd_la_SOURCES = ntpd.c
=back
+=head2 Plugin C<nginx>
+
+This plugin collects the number of connections and requests handeled by the
+C<nginx daemon> (speak: engineE<nbsp>X), a HTTP and mail server/proxy. It
+queries the page provided by the C<ngx_http_stub_status_module> module, which
+isn't compiled by default. Please refer to
+L<http://wiki.codemongers.com/NginxStubStatusModule> for more information on
+how to compile and configure nginx and this module.
+
+The following options are accepted by the C<nginx plugin>:
+
+=over 4
+
+=item B<URL> I<http://host/nginx_status>
+
+Sets the URL of the C<ngx_http_stub_status_module> output.
+
+=item B<User> I<Username>
+
+Optional user name needed for authentication.
+
+=item B<Password> I<Password>
+
+Optional password needed for authentication.
+
+=item B<CACert> I<File>
+
+File that holds one or more SSL certificates. If you want to use HTTPS you will
+possibly need this option. What CA certificates come bundled with C<libcurl>
+and are checked by default depends on the distribution you use.
+
+=back
+
=head2 Plugin C<ntpd>
=over 4
#include "configfile.h"
+#include <stddef.h>
+
#if HAVE_LIBPTHREAD
# include <pthread.h>
#endif
--- /dev/null
+/**
+ * collectd - src/nginx.c
+ * Copyright (C) 2006,2007 Florian octo Forster
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <curl/curl.h>
+
+static char *url = NULL;
+static char *user = NULL;
+static char *pass = NULL;
+static char *cacert = NULL;
+
+static CURL *curl = NULL;
+
+#define ABUFFER_SIZE 16384
+static char nginx_buffer[ABUFFER_SIZE];
+static int nginx_buffer_len = 0;
+static char nginx_curl_error[CURL_ERROR_SIZE];
+
+static const char *config_keys[] =
+{
+ "URL",
+ "User",
+ "Password",
+ "CACert"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+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) >= ABUFFER_SIZE)
+ {
+ len = (ABUFFER_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 config_set (char **var, const char *value)
+{
+ if (*var != NULL)
+ {
+ free (*var);
+ *var = NULL;
+ }
+
+ if ((*var = strdup (value)) == NULL)
+ return (1);
+ else
+ return (0);
+}
+
+static int config (const char *key, const char *value)
+{
+ if (strcasecmp (key, "url") == 0)
+ return (config_set (&url, value));
+ else if (strcasecmp (key, "user") == 0)
+ return (config_set (&user, value));
+ else if (strcasecmp (key, "password") == 0)
+ return (config_set (&pass, value));
+ else if (strcasecmp (key, "cacert") == 0)
+ return (config_set (&cacert, value));
+ else
+ return (-1);
+} /* int config */
+
+static int init (void)
+{
+ static char credentials[1024];
+
+ if (curl != NULL)
+ curl_easy_cleanup (curl);
+
+ if ((curl = curl_easy_init ()) == NULL)
+ {
+ ERROR ("nginx plugin: 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 plugin: 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);
+ }
+
+ return (0);
+} /* void init */
+
+static void submit (char *type, char *inst, long long value)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ if (strcpy (type, "nginx_connections") == 0)
+ values[0].gauge = value;
+ else if (strcpy (type, "nginx_requests") == 0)
+ values[0].counter = value;
+ else
+ return;
+
+ 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 (inst != NULL)
+ {
+ strncpy (vl.type_instance, inst, sizeof (vl.type_instance));
+ vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ }
+
+ plugin_dispatch_values (type, &vl);
+} /* void submit */
+
+static int nginx_read (void)
+{
+ int i;
+
+ char *ptr;
+ char *lines[16];
+ int lines_num = 0;
+
+ char *fields[16];
+ int fields_num;
+
+ if (curl == NULL)
+ return (-1);
+ if (url == NULL)
+ return (-1);
+
+ nginx_buffer_len = 0;
+ if (curl_easy_perform (curl) != 0)
+ {
+ WARNING ("nginx plugin: curl_easy_perform failed: %s", nginx_curl_error);
+ return (-1);
+ }
+
+ ptr = nginx_buffer;
+ while ((lines[lines_num] = strtok (ptr, "\n\r")) != NULL)
+ {
+ ptr = NULL;
+ lines_num++;
+
+ if (lines_num >= 16)
+ break;
+ }
+
+ /*
+ * Active connections: 291
+ * server accepts handled requests
+ * 16630948 16630948 31070465
+ * Reading: 6 Writing: 179 Waiting: 106
+ */
+ for (i = 0; i < lines_num; i++)
+ {
+ fields_num = strsplit (lines[i], fields,
+ (sizeof (fields) / sizeof (fields[0])));
+
+ if (fields_num == 3)
+ {
+ if ((strcmp (fields[0], "Active") == 0)
+ && (strcmp (fields[1], "connections:") == 0))
+ {
+ submit ("nginx_connections", "active", atoll (fields[2]));
+ }
+ else if ((atoll (fields[0]) != 0)
+ && (atoll (fields[1]) != 0)
+ && (atoll (fields[2]) != 0))
+ {
+ submit ("nginx_requests", NULL, atoll (fields[2]));
+ }
+ }
+ else if (fields_num == 6)
+ {
+ if ((strcmp (fields[0], "Reading:") == 0)
+ && (strcmp (fields[2], "Writing:") == 0)
+ && (strcmp (fields[4], "Waiting:") == 0))
+ {
+ submit ("nginx_connections", "reading", atoll (fields[1]));
+ submit ("nginx_connections", "writing", atoll (fields[3]));
+ submit ("nginx_connections", "waiting", atoll (fields[5]));
+ }
+ }
+ }
+
+ nginx_buffer_len = 0;
+
+ return (0);
+} /* int nginx_read */
+
+void module_register (void)
+{
+ plugin_register_config ("nginx", config, config_keys, config_keys_num);
+ plugin_register_init ("nginx", init);
+ plugin_register_read ("nginx", nginx_read);
+} /* void module_register */
+
+/*
+ * vim: set shiftwidth=2 softtabstop=2 tabstop=8 :
+ */
#include "common.h"
#include "plugin.h"
-#if !KERNEL_LINUX
+#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME
# error "No applicable input method."
#endif
-#define TCP_STATE_LISTEN 10
-#define TCP_STATE_MAX 11
+#if KERNEL_LINUX
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_SYSCTLBYNAME
+# include <sys/socketvar.h>
+# include <sys/sysctl.h>
+# include <net/route.h>
+# include <netinet/in.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# include <netinet/ip6.h>
+# include <netinet/in_pcb.h>
+# include <netinet/ip_var.h>
+# include <netinet/tcp.h>
+# include <netinet/tcpip.h>
+# include <netinet/tcp_seq.h>
+# include <netinet/tcp_var.h>
+#endif /* HAVE_SYSCTLBYNAME */
+
+#if KERNEL_LINUX
+static const char *tcp_state[] =
+{
+ "", /* 0 */
+ "ESTABLISHED",
+ "SYN_SENT",
+ "SYN_RECV",
+ "FIN_WAIT1",
+ "FIN_WAIT2",
+ "TIME_WAIT",
+ "CLOSED",
+ "CLOSE_WAIT",
+ "LAST_ACK",
+ "LISTEN", /* 10 */
+ "CLOSING"
+};
+
+# define TCP_STATE_LISTEN 10
+# define TCP_STATE_MIN 1
+# define TCP_STATE_MAX 11
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_SYSCTLBYNAME
+static const char *tcp_state[] =
+{
+ "CLOSED",
+ "LISTEN",
+ "SYN_SENT",
+ "SYN_RECV",
+ "ESTABLISHED",
+ "CLOSE_WAIT",
+ "FIN_WAIT1",
+ "CLOSING",
+ "LAST_ACK",
+ "FIN_WAIT2",
+ "TIME_WAIT"
+};
+
+# define TCP_STATE_LISTEN 1
+# define TCP_STATE_MIN 0
+# define TCP_STATE_MAX 10
+#endif /* HAVE_SYSCTLBYNAME */
#define PORT_COLLECT_LOCAL 0x01
#define PORT_COLLECT_REMOTE 0x02
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-static const char *tcp_state[] =
-{
- "", /* 0 */
- "ESTABLISHED",
- "SYN_SENT",
- "SYN_RECV",
- "FIN_WAIT1",
- "FIN_WAIT2",
- "TIME_WAIT",
- "CLOSE",
- "CLOSE_WAIT",
- "LAST_ACK",
- "LISTEN", /* 10 */
- "CLOSING"
-};
-
static int port_collect_listening = 0;
static port_entry_t *port_list_head = NULL;
{
port_entry_t *pe = NULL;
- if ((state == 0) || (state > TCP_STATE_MAX))
+ if ((state > TCP_STATE_MAX)
+#if TCP_STATE_MIN > 0
+ || (state < TCP_STATE_MIN)
+#endif
+ )
{
NOTICE ("tcpconns plugin: Ignoring connection with unknown state 0x%02x.",
state);
return (0);
} /* int conn_handle_ports */
+#if KERNEL_LINUX
static int conn_handle_line (char *buffer)
{
char *fields[32];
return (0);
} /* int conn_read_file */
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_SYSCTLBYNAME
+#endif /* HAVE_SYSCTLBYNAME */
static int conn_config (const char *key, const char *value)
{
return (0);
} /* int conn_config */
+#if KERNEL_LINUX
static int conn_init (void)
{
if (port_list_head == NULL)
return (0);
} /* int conn_read */
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_SYSCTLBYNAME
+static int conn_read (void)
+{
+ int status;
+ char *buffer;
+ size_t buffer_len;;
+
+ struct xinpgen *in_orig;
+ struct xinpgen *in_ptr;
+
+ conn_reset_port_entry ();
+
+ buffer_len = 0;
+ status = sysctlbyname ("net.inet.tcp.pcblist", NULL, &buffer_len, 0, 0);
+ if (status < 0)
+ {
+ ERROR ("tcpconns plugin: sysctlbyname failed.");
+ return (-1);
+ }
+
+ buffer = (char *) malloc (buffer_len);
+ if (buffer == NULL)
+ {
+ ERROR ("tcpconns plugin: malloc failed.");
+ return (-1);
+ }
+
+ status = sysctlbyname ("net.inet.tcp.pcblist", buffer, &buffer_len, 0, 0);
+ if (status < 0)
+ {
+ ERROR ("tcpconns plugin: sysctlbyname failed.");
+ sfree (buffer);
+ return (-1);
+ }
+
+ if (buffer_len <= sizeof (struct xinpgen))
+ {
+ ERROR ("tcpconns plugin: (buffer_len <= sizeof (struct xinpgen))");
+ sfree (buffer);
+ return (-1);
+ }
+
+ in_orig = (struct xinpgen *) buffer;
+ for (in_ptr = (struct xinpgen *) (((char *) in_orig) + in_orig->xig_len);
+ in_ptr->xig_len > sizeof (struct xinpgen);
+ in_ptr = (struct xinpgen *) (((char *) in_ptr) + in_ptr->xig_len))
+ {
+ struct tcpcb *tp = &((struct xtcpcb *) in_ptr)->xt_tp;
+ struct inpcb *inp = &((struct xtcpcb *) in_ptr)->xt_inp;
+ struct xsocket *so = &((struct xtcpcb *) in_ptr)->xt_socket;
+
+ /* Ignore non-TCP sockets */
+ if (so->xso_protocol != IPPROTO_TCP)
+ continue;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (inp->inp_gencnt > in_orig->xig_gen)
+ continue;
+
+ if (((inp->inp_vflag & INP_IPV4) == 0)
+ && ((inp->inp_vflag & INP_IPV6) == 0))
+ continue;
+
+ conn_handle_ports (inp->inp_lport, inp->inp_fport, tp->t_state);
+ } /* for (in_ptr) */
+
+ in_orig = NULL;
+ in_ptr = NULL;
+ sfree (buffer);
+
+ conn_submit_all ();
+
+ return (0);
+} /* int conn_read */
+#endif /* HAVE_SYSCTLBYNAME */
void module_register (void)
{
plugin_register_config ("tcpconns", conn_config,
config_keys, config_keys_num);
+#if KERNEL_LINUX
plugin_register_init ("tcpconns", conn_init);
+#endif
plugin_register_read ("tcpconns", conn_read);
} /* void module_register */
memcached_items value:GAUGE:0:U
memcached_octets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
memcached_ops value:COUNTER:0:134217728
+nginx_connections value:GAUGE:0:U
+nginx_requests value:COUNTER:0:134217728
percent percent:GAUGE:0:100.1
ping ping:GAUGE:0:65535
power value:GAUGE:0:U