From: Florian Forster Date: Sat, 28 Feb 2009 11:12:54 +0000 (+0100) Subject: protocols plugin: Add a plugin which collets protocol information. X-Git-Tag: collectd-4.7.0~126 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=15f09880316647c8887953acbeaf551f32a7e0a9 protocols plugin: Add a plugin which collets protocol information. Currently a Linux only plugin. This plugin collects information about IP, TCP, UDP, etc. Thanks to Ulf Zimmermann for his (indirect) suggestion ;) --- diff --git a/README b/README index a6a53544..7889d2c7 100644 --- a/README +++ b/README @@ -179,6 +179,9 @@ Features - processes Process counts: Number of running, sleeping, zombie, ... processes. + - protocols + Counts various aspects of network protocols such as IP, TCP, UDP, etc. + - rrdcached RRDtool caching daemon (RRDcacheD) statistics. diff --git a/configure.in b/configure.in index 401604f9..c772f36c 100644 --- a/configure.in +++ b/configure.in @@ -2947,6 +2947,7 @@ plugin_multimeter="no" plugin_nfs="no" plugin_perl="no" plugin_processes="no" +plugin_protocols="no" plugin_serial="no" plugin_swap="no" plugin_tape="no" @@ -2971,6 +2972,7 @@ then plugin_memory="yes" plugin_nfs="yes" plugin_processes="yes" + plugin_protocols="yes" plugin_serial="yes" plugin_swap="yes" plugin_tcpconns="yes" @@ -3180,6 +3182,7 @@ AC_PLUGIN([ping], [$with_liboping], [Network latency statistics]) AC_PLUGIN([postgresql], [$with_libpq], [PostgreSQL database statistics]) AC_PLUGIN([powerdns], [yes], [PowerDNS statistics]) AC_PLUGIN([processes], [$plugin_processes], [Process statistics]) +AC_PLUGIN([protocols], [$plugin_protocols], [Protocol (IP, TCP, ...) statistics]) AC_PLUGIN([rrdcached], [$librrd_rrdc_update], [RRDTool output plugin]) AC_PLUGIN([rrdtool], [$with_librrd], [RRDTool output plugin]) AC_PLUGIN([sensors], [$with_libsensors], [lm_sensors statistics]) diff --git a/src/Makefile.am b/src/Makefile.am index f4f2be9f..5401bba7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -691,6 +691,14 @@ processes_la_LIBADD += -lkvm endif endif +if BUILD_PLUGIN_PROTOCOLS +pkglib_LTLIBRARIES += protocols.la +protocols_la_SOURCES = protocols.c +protocols_la_LDFLAGS = -module -avoid-version +collectd_LDADD += "-dlopen" protocols.la +collectd_DEPENDENCIES += protocols.la +endif + if BUILD_PLUGIN_RRDCACHED pkglib_LTLIBRARIES += rrdcached.la rrdcached_la_SOURCES = rrdcached.c utils_rrdcreate.c utils_rrdcreate.h diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 1ab43607..391f0f32 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -2287,6 +2287,39 @@ slashes. =back +=head2 Plugin C + +Collects a lot of information about various network protocols, such as I, +I, I, etc. + +Available configuration options: + +=over 4 + +=item B I + +Selects whether or not to select a specific value. The string being matched is +of the form "I:I", where I will be used as the +plugin instance and I will be used as type instance. An example of +the string being used would be C. + +You can use regular expressions to match a large number of values with just one +configuration option. To select all "extended" I values, you could use the +following statement: + + Value "/^TcpExt:/" + +Whether only matched values are selected or all matched values are ignored +depends on the B. By default, only matched values are selected. +If no value is configured at all, all values will be selected. + +=item B B|B + +If set to B, inverts the selection made by B, i.Ee. all +matching values will be ignored. + +=back + =head2 Plugin C The C plugin uses the RRDTool accelerator daemon, L, diff --git a/src/common.c b/src/common.c index ef808851..b37db889 100644 --- a/src/common.c +++ b/src/common.c @@ -253,7 +253,7 @@ int strsplit (char *string, char **fields, size_t size) break; } - return (i); + return ((int) i); } int strjoin (char *dst, size_t dst_len, diff --git a/src/common.h b/src/common.h index 72098083..113f0440 100644 --- a/src/common.h +++ b/src/common.h @@ -98,7 +98,7 @@ ssize_t swrite (int fd, const void *buf, size_t count); * * DESCRIPTION * Splits a string into parts and stores pointers to the parts in `fields'. - * The characters split at are ` ' (space) and "\t" (tab). + * The characters split at are: " ", "\t", "\r", and "\n". * * PARAMETERS * `string' String to split. This string will be modified. `fields' will diff --git a/src/protocols.c b/src/protocols.c new file mode 100644 index 00000000..75e9a1c4 --- /dev/null +++ b/src/protocols.c @@ -0,0 +1,248 @@ +/** + * collectd - src/protocols.c + * Copyright (C) 2009 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; 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: + * Florian octo Forster + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" +#include "utils_ignorelist.h" + +#if !KERNEL_LINUX +# error "No applicable input method." +#endif + +#define SNMP_FILE "/proc/net/snmp" +#define NETSTAT_FILE "/proc/net/netstat" + +/* + * Global variables + */ +static const char *config_keys[] = +{ + "Value", + "IgnoreSelected", +}; +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); + +static ignorelist_t *values_list = NULL; + +/* + * Functions + */ +static void submit (const char *protocol_name, + const char *str_key, const char *str_value) +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + char *tmp_ptr; + + errno = 0; + tmp_ptr = NULL; + values[0].counter = (counter_t) strtoll (str_value, &tmp_ptr, + /* base = */ 0); + if ((errno != 0) || (tmp_ptr == str_value)) + { + ERROR ("protocols plugin: Parsing string as integer failed: %s", + str_value); + return; + } + + vl.values = values; + vl.values_len = 1; + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "protocols", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, protocol_name, sizeof (vl.plugin_instance)); + sstrncpy (vl.type, "protocol_counter", sizeof (vl.type)); + sstrncpy (vl.type_instance, str_key, sizeof (vl.type_instance)); + + plugin_dispatch_values (&vl); +} /* void submit */ + +static int read_file (const char *path) +{ + FILE *fh; + char key_buffer[4096]; + char value_buffer[4096]; + char *key_ptr; + char *value_ptr; + char *key_fields[256]; + char *value_fields[256]; + int key_fields_num; + int value_fields_num; + int status; + int i; + + fh = fopen (path, "r"); + if (fh == NULL) + { + ERROR ("protocols plugin: fopen (%s) failed: %s.", + path, sstrerror (errno, key_buffer, sizeof (key_buffer))); + return (-1); + } + + status = -1; + while (42) + { + clearerr (fh); + key_ptr = fgets (key_buffer, sizeof (key_buffer), fh); + if (key_ptr == NULL) + { + if (feof (fh) != 0) + { + status = 0; + break; + } + else if (ferror (fh) != 0) + { + ERROR ("protocols plugin: Reading from %s failed.", path); + break; + } + else + { + ERROR ("protocols plugin: fgets failed for an unknown reason."); + break; + } + } /* if (key_ptr == NULL) */ + + value_ptr = fgets (value_buffer, sizeof (value_buffer), fh); + if (value_ptr == NULL) + { + ERROR ("protocols plugin: read_file (%s): Could not read values line.", + path); + break; + } + + key_ptr = strchr (key_buffer, ':'); + if (key_ptr == NULL) + { + ERROR ("protocols plugin: Could not find protocol name in keys line."); + break; + } + *key_ptr = 0; + key_ptr++; + + value_ptr = strchr (value_buffer, ':'); + if (value_ptr == NULL) + { + ERROR ("protocols plugin: Could not find protocol name " + "in values line."); + break; + } + *value_ptr = 0; + value_ptr++; + + if (strcmp (key_buffer, value_buffer) != 0) + { + ERROR ("protocols plugin: Protocol names in keys and values lines " + "don't match: `%s' vs. `%s'.", + key_buffer, value_buffer); + break; + } + + + key_fields_num = strsplit (key_ptr, + key_fields, STATIC_ARRAY_SIZE (key_fields)); + value_fields_num = strsplit (value_ptr, + value_fields, STATIC_ARRAY_SIZE (value_fields)); + + if (key_fields_num != value_fields_num) + { + ERROR ("protocols plugin: Number of fields in keys and values lines " + "dont match: %i vs %i.", + key_fields_num, value_fields_num); + break; + } + + for (i = 0; i < key_fields_num; i++) + { + if (values_list != NULL) + { + char match_name[2 * DATA_MAX_NAME_LEN]; + + ssnprintf (match_name, sizeof (match_name), "%s:%s", + key_buffer, key_fields[i]); + + if (ignorelist_match (values_list, match_name)) + continue; + } /* if (values_list != NULL) */ + + submit (key_buffer, key_fields[i], value_fields[i]); + } /* for (i = 0; i < key_fields_num; i++) */ + } /* while (42) */ + + fclose (fh); + + return (status); +} /* int read_file */ + +static int protocols_read (void) +{ + int status; + int success = 0; + + status = read_file (SNMP_FILE); + if (status == 0) + success++; + + status = read_file (NETSTAT_FILE); + if (status == 0) + success++; + + if (success == 0) + return (-1); + + return (0); +} /* int protocols_read */ + +static int protocols_config (const char *key, const char *value) +{ + if (values_list == NULL) + values_list = ignorelist_create (/* invert = */ 1); + + if (strcasecmp (key, "Value") == 0) + { + ignorelist_add (values_list, value); + } + else if (strcasecmp (key, "IgnoreSelected") == 0) + { + int invert = 1; + if ((strcasecmp (value, "True") == 0) + || (strcasecmp (value, "Yes") == 0) + || (strcasecmp (value, "On") == 0)) + invert = 0; + ignorelist_set_invert (values_list, invert); + } + else + { + return (-1); + } + + return (0); +} /* int protocols_config */ + +void module_register (void) +{ + plugin_register_config ("protocols", protocols_config, + config_keys, config_keys_num); + plugin_register_read ("protocols", protocols_read); +} /* void module_register */ + +/* vim: set sw=2 sts=2 et : */ diff --git a/src/types.db b/src/types.db index 82b5b4f3..cde4e309 100644 --- a/src/types.db +++ b/src/types.db @@ -86,6 +86,7 @@ pg_xact value:COUNTER:0:U ping ping:GAUGE:0:65535 players value:GAUGE:0:1000000 power value:GAUGE:0:U +protocol_counter value:COUNTER:0:U ps_count processes:GAUGE:0:1000000, threads:GAUGE:0:1000000 ps_cputime user:COUNTER:0:16000000, syst:COUNTER:0:16000000 ps_pagefaults minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807