From: Edgar Fuß Date: Mon, 13 Jul 2020 14:35:12 +0000 (+0200) Subject: Add a Count option to snmp plugin (minus indent) X-Git-Tag: collectd-5.12.0~22^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=193ea7dc13acdf5783be1fabd7aaef631974d3b5;p=thirdparty%2Fcollectd.git Add a Count option to snmp plugin (minus indent) Add a Count option to the snmp plugin allowing to gather the number of table entries (matching given criteria) rather than their values. This is especially useful in combination with the recently introduced Filter options. Example: Count number of total/connected stations on a (Lancom) Access Point. Indentation changes to existing code are deferred to the next commit in order ease review. --- diff --git a/src/collectd-snmp.pod b/src/collectd-snmp.pod index 5e99ba335..53689c199 100644 --- a/src/collectd-snmp.pod +++ b/src/collectd-snmp.pod @@ -30,6 +30,22 @@ collectd-snmp - Documentation of collectd's C #FilterValues "1", "2" Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets" + + Type "counter" + PluginInstance "stations_total" + Table true + Count true + Values "SNMPv2-SMI::enterprises.2356.11.1.3.32.1.10" # SNMPv2-SMI::enterprises.lancom-systems.lcos.lcsStatus.lcsStatusWlan.lcsStatusWlanStationTableTable.lcsStatusWlanStationTableEntry.lcsStatusWlanStationTableEntryState + + + Type "counter" + PluginInstance "stations_connected" + Table true + Count true + Values "SNMPv2-SMI::enterprises.2356.11.1.3.32.1.10" # SNMPv2-SMI::enterprises.lancom-systems.lcos.lcsStatus.lcsStatusWlan.lcsStatusWlanStationTableTable.lcsStatusWlanStationTableEntry.lcsStatusWlanStationTableEntryState + FilterOID "SNMPv2-SMI::enterprises.2356.11.1.3.32.1.10" + FilterValues "3" # eConnected + Address "192.168.0.2" @@ -119,13 +135,14 @@ written. When B is set to B, the OIDs given to B, B, B, B and B (see below) are queried using -the C SNMP command until the subtree is left. After all -the lists (think: all columns of the table) have been read B values -sets will be dispatches and, eventually, several files will be written. If you +the C SNMP command until the subtree is left. After all the lists +(think: all columns of the table) have been read, either (B set to B) +B value sets will be dispatched and, eventually, several files will be +written, or (B set to B) one single value will be dispatched. If you configure a B (see above) which needs more than one data source (for example C which needs C and C) you will need to specify more -than one (two, in the example case) OIDs with the B option. This has -nothing to do with the B
setting. +than one (two, in the example case) OIDs with the B option and can't use +the B option. This has nothing to do with the B
setting. For example, if you want to query the number of users on a system, you can use C. This is one value and belongs to one @@ -184,7 +201,8 @@ as the value. Prefix may be set for values with use of appropriate B, B and B options. -When B
is set to I these options has no effect. +When B
is set to I or B is set to I, these options +have no effect. Defaults: When no one of these options is configured explicitly, B defaults to an empty string. @@ -200,7 +218,8 @@ B and B respectively. If set, I is preprended to values received by querying the agent. -When B
is set to I these options has no effect. +When B
is set to I or B is set to I, these options +have no effect. The C is an example where you need this setting: It has voltages of the inlets, outlets and the battery of an UPS. However, it doesn't provide a @@ -243,6 +262,16 @@ If B
is set to I, each I must be the OID of exactly one value, e.Eg. C for the third counter of incoming traffic. +=item B I + +Instead of dispatching one or multiple values per Table entry containing the +I(s) given in the B option, just dispatch a single count giving the +number of entries that would have been dispatched. This is especially useful when +combined with the filtering options (see below) to count the number of entries in +a Table matching certain criteria. + +When B
is set to I, this option has no effect. + =item B I The gauge-values returned by the SNMP-agent are multiplied by I. This diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 16b222076..6620ccf25 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -1543,6 +1543,22 @@ # PluginInstanceOID "IF-MIB::ifDescr" # Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets" # +# +# Type "counter" +# PluginInstance "stations_total" +# Table true +# Count true +# Values "SNMPv2-SMI::enterprises.2356.11.1.3.32.1.10" # SNMPv2-SMI::enterprises.lancom-systems.lcos.lcsStatus.lcsStatusWlan.lcsStatusWlanStationTableTable.lcsStatusWlanStationTableEntry.lcsStatusWlanStationTableEntryState +# +# +# Type "counter" +# PluginInstance "stations_connected" +# Table true +# Count true +# Values "SNMPv2-SMI::enterprises.2356.11.1.3.32.1.10" # SNMPv2-SMI::enterprises.lancom-systems.lcos.lcsStatus.lcsStatusWlan.lcsStatusWlanStationTableTable.lcsStatusWlanStationTableEntry.lcsStatusWlanStationTableEntryState +# FilterOID "SNMPv2-SMI::enterprises.2356.11.1.3.32.1.10" +# FilterValues "3" # eConnected +# # # # Address "192.168.0.2" diff --git a/src/snmp.c b/src/snmp.c index 98da2b824..1f2b4eec6 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -71,6 +71,7 @@ struct data_definition_s { char **ignores; size_t ignores_len; bool invert_match; + bool count; }; typedef struct data_definition_s data_definition_t; @@ -473,7 +474,9 @@ static int csnmp_config_add_data(oconfig_item_t *ci) { status = cf_util_get_boolean(option, &t); if (status == 0) ignorelist_set_invert(dd->ignorelist, /* invert = */ !t); - } else { + } else if (strcasecmp("Count", option->key) == 0) + status = cf_util_get_boolean(option, &dd->count); + else { WARNING("snmp plugin: data %s: Option `%s' not allowed here.", dd->name, option->key); status = -1; @@ -513,6 +516,13 @@ static int csnmp_config_add_data(oconfig_item_t *ci) { dd->name); } } else { + if (dd->count) { + WARNING("snmp plugin: data %s: Option `Count' is ignored when `Table' " + "set to `false'.", + dd->name); + } + } + if (!dd->is_table || dd->count) { if (dd->plugin_instance.oid.oid_len > 0) { WARNING("snmp plugin: data %s: Option `PluginInstanceOID' will be " "ignored.", @@ -525,20 +535,18 @@ static int csnmp_config_add_data(oconfig_item_t *ci) { } if (dd->type_instance.prefix) { WARNING("snmp plugin: data %s: Option `TypeInstancePrefix' is ignored " - "when `Table' " - "set to `false'.", + "when `Table' set to `false' or `Count' set to `true'.", dd->name); } if (dd->plugin_instance.prefix) { WARNING("snmp plugin: data %s: Option `PluginInstancePrefix' is " - "ignored when " - "`Table' set to `false'.", + "ignored when `Table' set to `false' or `Count' set to `true'.", dd->name); } if (dd->host.prefix) { WARNING( "snmp plugin: data %s: Option `HostPrefix' is ignored when `Table' " - "set to `false'.", + "set to `false' or `Count' set to `true'.", dd->name); } } @@ -1295,7 +1303,8 @@ static int csnmp_dispatch_table(host_definition_t *host, csnmp_cell_char_t *plugin_instance_cells, csnmp_cell_char_t *hostname_cells, csnmp_cell_char_t *filter_cells, - csnmp_cell_value_t **value_cells) { + csnmp_cell_value_t **value_cells, + bool count_values) { const data_set_t *ds; value_list_t vl = VALUE_LIST_INIT; @@ -1308,12 +1317,17 @@ static int csnmp_dispatch_table(host_definition_t *host, size_t i; bool have_more; oid_t current_suffix; + size_t count; ds = plugin_get_ds(data->type); if (!ds) { ERROR("snmp plugin: DataSet `%s' not defined.", data->type); return -1; } + if (count_values) { + assert(ds->ds_num == 1); + count = 0; + } else assert(ds->ds_num == data->values_len); assert(data->values_len > 0); @@ -1478,6 +1492,9 @@ static int csnmp_dispatch_table(host_definition_t *host, continue; } + if (count_values) { + count++; + } else { /* set vl.host */ if (data->host.configured) { char temp[DATA_MAX_NAME_LEN]; @@ -1542,6 +1559,7 @@ static int csnmp_dispatch_table(host_definition_t *host, /* prevent leakage of pointer to local variable. */ vl.values_len = 0; vl.values = NULL; + } if (type_instance_cells != NULL) type_instance_cell_ptr = type_instance_cell_ptr->next; @@ -1549,6 +1567,25 @@ static int csnmp_dispatch_table(host_definition_t *host, value_cell_ptr[0] = value_cell_ptr[0]->next; } /* while (have_more) */ + if (count_values) { + sstrncpy(vl.host, host->name, sizeof(vl.host)); + sstrncpy(vl.plugin, data->plugin_name, sizeof(vl.plugin)); + sstrncpy(vl.type, data->type, sizeof(vl.type)); + if (data->type_instance.value) + sstrncpy(vl.type_instance, data->type_instance.value, + sizeof(vl.type_instance)); + if (data->plugin_instance.value) + sstrncpy(vl.plugin_instance, data->plugin_instance.value, + sizeof(vl.plugin_instance)); + vl.values_len = 1; + vl.values = malloc(sizeof(*vl.values)); + if (vl.values == NULL) + return -1; + vl.values[0].counter = count; + plugin_dispatch_values(&vl); + sfree(vl.values); + } + return 0; } /* int csnmp_dispatch_table */ @@ -1611,6 +1648,21 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { return -1; } + if (data->count) { + if (ds->ds_num != 1) { + ERROR("snmp plugin: DataSet `%s' requires %" PRIsz + " values, but `Count' option only delivers one", + data->type, ds->ds_num); + return -1; + } + /* the first `ds' means `data set', the second means `data source' */ + if (ds->ds->type != DS_TYPE_COUNTER) { + ERROR("snmp plugin: DataSet `%s' needs to be of COUNTER" + " type for `Count' option", + data->type); + return -1; + } + } else { if (ds->ds_num != data->values_len) { ERROR("snmp plugin: DataSet `%s' requires %" PRIsz " values, but config talks " @@ -1618,6 +1670,7 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { data->type, ds->ds_num, data->values_len); return -1; } + } assert(data->values_len > 0); for (i = 0; i < data->values_len; i++) @@ -1981,7 +2034,7 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { if (status == 0) csnmp_dispatch_table(host, data, type_instance_cells_head, plugin_instance_cells_head, hostname_cells_head, - filter_cells_head, value_cells_head); + filter_cells_head, value_cells_head, data->count); /* Free all allocated variables here */ while (type_instance_cells_head != NULL) {