From def529326cb326ccc6ce33bbd6b39b92edbc0b76 Mon Sep 17 00:00:00 2001 From: Lubos Stanek Date: Wed, 25 Oct 2006 16:23:42 +0200 Subject: [PATCH] sensors plugin: Improve the support for multiple chips and add an ignore functionality. Date: Tue, 24 Oct 2006 19:09:35 +0200 From: Lubo?? Stan??k To: collectd@verplant.org Subject: Re: [collectd] 3.10.1 - proposed patch to extend sensors plugin Enhancements: - precise sensor feature selection (chip-bus-address/type-feature) in the ExtendedSensorNaming mode - more sensor features (finite list) - honor sensors.conf's ignored - config Sensor option - config IgnoreSelected option - config ExtendedSensorNaming option - modified DS'es to include proper information about type in the ExtendedSensorNaming mode - /type- differs from yours because of the conflict between the type and the old DS in the ExtendedSensorNaming mode - the contrib/collection.cgi is modified to support both modes --- README | 2 +- contrib/collection.cgi | 16 +-- src/collectd.conf.in | 24 ++++ src/collectd.conf.pod | 60 +++++++++ src/collectd.pod | 2 +- src/sensors.c | 321 +++++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 380 insertions(+), 45 deletions(-) diff --git a/README b/README index 511683f7..ac1ba15e 100644 --- a/README +++ b/README @@ -65,7 +65,7 @@ Features (Number of running, sleeping, zombie, ... processes) - Sensors - (System temperatured and fan rotation speeds) + (lm_sensors voltages, temperatures and fan rotation speeds) - Serial (RX and TX of serial interfaces) diff --git a/contrib/collection.cgi b/contrib/collection.cgi index a0fc4fc9..c1ee8e7e 100755 --- a/contrib/collection.cgi +++ b/contrib/collection.cgi @@ -251,9 +251,9 @@ our $GraphDefs; 'DEF:temp_avg={file}:value:AVERAGE', 'DEF:temp_min={file}:value:MIN', 'DEF:temp_max={file}:value:MAX', - "AREA:temp_max#$HalfBlue", + "AREA:temp_max#$HalfMagenta", "AREA:temp_min#$Canvas", - "LINE1:temp_avg#$FullBlue:RPM", + "LINE1:temp_avg#$FullMagenta:RPM", 'GPRINT:temp_min:MIN:%4.1lf Min,', 'GPRINT:temp_avg:AVERAGE:%4.1lf Avg,', 'GPRINT:temp_max:MAX:%4.1lf Max,', @@ -275,9 +275,9 @@ our $GraphDefs; 'DEF:temp_avg={file}:value:AVERAGE', 'DEF:temp_min={file}:value:MIN', 'DEF:temp_max={file}:value:MAX', - "AREA:temp_max#$HalfBlue", + "AREA:temp_max#$HalfRed", "AREA:temp_min#$Canvas", - "LINE1:temp_avg#$FullBlue:Temperature", + "LINE1:temp_avg#$FullRed:Temperature", 'GPRINT:temp_min:MIN:%4.1lf Min,', 'GPRINT:temp_avg:AVERAGE:%4.1lf Avg,', 'GPRINT:temp_max:MAX:%4.1lf Max,', @@ -839,9 +839,9 @@ our $GraphDefs; 'DEF:temp_avg={file}:value:AVERAGE', 'DEF:temp_min={file}:value:MIN', 'DEF:temp_max={file}:value:MAX', - "AREA:temp_max#$HalfBlue", + "AREA:temp_max#$HalfRed", "AREA:temp_min#$Canvas", - "LINE1:temp_avg#$FullBlue:Value", + "LINE1:temp_avg#$FullRed:Value", 'GPRINT:temp_min:MIN:%4.1lf Min,', 'GPRINT:temp_avg:AVERAGE:%4.1lf Avg,', 'GPRINT:temp_max:MAX:%4.1lf Max,', @@ -1058,7 +1058,7 @@ our $GraphArgs = delay => ['-t', 'NTPd peer delay ({inst})', '-v', 'Seconds'], df => ['-t', '{host}:{inst} usage', '-v', 'Percent', '-l', '0'], disk => ['-t', '{host} disk {inst} usage', '-v', 'Byte/s'], - fanspeed => ['-t', '{host} fanspeed {inst}', '-v', 'rpm'], + fanspeed => ['-t', '{host} fanspeed {inst}', '-v', 'RPM'], frequency_offset => ['-t', 'NTPd frequency offset ({inst})', '-v', 'Parts per million'], hddtemp => ['-t', '{host} hdd temperature {inst}', '-v', '°Celsius'], if_errors => ['-t', '{host} {inst} errors', '-v', 'Errors/s'], @@ -1088,7 +1088,7 @@ our $GraphArgs = traffic => ['-t', '{host} {inst} traffic', '-v', 'Bit/s'], users => ['-t', '{host} users', '-v', 'Users'], multimeter => ['-t', '{host} multimeter', '-v', 'Value'], - voltage => ['-t', '{host} voltage', '-v', 'Volts'], + voltage => ['-t', '{host} voltage {inst}', '-v', 'Volts'], vs_threads => ['-t', '{host} threads', '-v', 'Threads'], vs_memory => ['-t', '{host} memory usage', '-v', 'Bytes'], vs_processes => ['-t', '{host} processes', '-v', 'Processes'], diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 29035abf..e4e3f06c 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -83,6 +83,30 @@ # Process name # +# +## Collect required sensors. +## +## Default sensors and .rrd files names +## compatible with old .rrd files (temp and fan). +# +# ExtendedSensorNaming false +# Sensor it8712-temp1 +# Sensor it8712-fan3 +# Sensor it8712-in8 +## +## Extended sensors and .rrd files names break compatibility +## with previous naming and .rrd files, +## see collectd.conf(5) for detailed information. +# +# ExtendedSensorNaming true +# Sensor it8712-isa-0290/temperature_sensor-temp1 +# Sensor it8712-isa-0290/fanspeed_sensor-fan3 +# Sensor it8712-isa-0290/voltage_sensor-in8 +## +## Reverse sensors sellection? +# IgnoreSelected false +# + # # Interface eth0 # IgnoreSelected false diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 7e4b858e..e46d0713 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -224,6 +224,66 @@ multiple hosts. Sets the Time-To-Live of generated ICMP packets. + +=head2 Plugin C + +=over 4 + +=item B I|I + +If set to I this option switches on the extended sensors +and RRD files naming. + +Sensors get names like I +(e.g. I) and RRD files are therefore +stored in a standalone directory inside the B directory and get +names like I +(e.g. I). + +The B option breaks the compatibility with previous +sensors and RRD files naming and the place where RRDs are stored. If you turn +it on the plugin will create new RRD files in a standalone directory inside +the B directory and without previous history. You can rename +previous RRD files to the new ones to continue collecting data into the same +RRDs. + +If not set or set to I the extended naming is not active. Sensors +get names like I (e.g. I) and RRD files +are stored in the main B directory and get names like +I (e.g. I). +You simply continue using the plugin the old way and additionally also +getting data for newly added sensors in this mode. + +Default setting is I. + +=item B I or B I + +Both options select the name of the sensor which you want to collect. +The naming scheme is dependent on the state of the B +option (see previous paragraph). Both options can also deselect the +sensor according to the B option (see below). + +For example the option "B I" will cause +the collectd to gather data for the voltage sensor I +of the I chip in case of the B option +is set to I. + +And likewise the option "B I" will +cause the collectd to gather data for the voltage sensor I of the I +on the isa bus at the address 0290 in case of the B +option set to I. + +=item B I|I + +If no configuration if given, the B-plugin will collect data from +all sensors. This may not be practical, especially for uninteresting sensors. +Thus, you can use the B-option to pick the sensors you're +interested in. Sometimes, however, it's easier/prefered to collect all +sensors I a few ones. This option enables you to +do that: By setting B to I the effect of +B is inversed: All selected sensors are ignored and all +other sensors are collected. + =back =head2 Plugin C diff --git a/src/collectd.pod b/src/collectd.pod index 0e1adc50..aff967df 100644 --- a/src/collectd.pod +++ b/src/collectd.pod @@ -421,7 +421,7 @@ The DS'es depend on the module creating the RRD files: DS:paging:GAUGE:HEARTBEAT:0:65535 DS:blocked:GAUGE:HEARTBEAT:0:65535 -=item lm_sensors (FchipE>-IfeatureE>.rrd>) +=item lm_sensors (FchipE>-IfeatureE>.rrd>) and lm_sensors (F>-IbusE>-IaddressE>/ItypeE>-IfeatureE>.rrd>) DS:value:GAUGE:HEARTBEAT:U:U diff --git a/src/sensors.c b/src/sensors.c index 940120c6..940b4b4c 100644 --- a/src/sensors.c +++ b/src/sensors.c @@ -18,11 +18,22 @@ * * Authors: * Florian octo Forster + * + * Lubos Stanek Wed Oct 25, 2006 + * - config ExtendedSensorNaming option + * - precise sensor feature selection (chip-bus-address/type-feature) + * with ExtendedSensorNaming + * - more sensor features (finite list) + * - honor sensors.conf's ignored + * - config Sensor option + * - config IgnoreSelected option **/ #include "collectd.h" #include "common.h" #include "plugin.h" +#include "configfile.h" +#include "utils_debug.h" #define MODULE_NAME "sensors" @@ -40,8 +51,6 @@ #define BUFSIZE 512 -static char *filename_format = "sensors-%s.rrd"; - static char *ds_def[] = { "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U", @@ -49,17 +58,195 @@ static char *ds_def[] = }; static int ds_num = 1; +/* old naming */ +static char *filename_format = "sensors-%s.rrd"; +/* end old naming */ + +/* new naming */ +static char *sensor_filename_format = "lm_sensors-%s.rrd"; + +static char *sensor_voltage_ds_def[] = +{ + "DS:voltage:GAUGE:"COLLECTD_HEARTBEAT":U:U", + NULL +}; +static int sensor_voltage_ds_num = 1; + +#define SENSOR_TYPE_UNKNOWN 0 +#define SENSOR_TYPE_VOLTAGE 1 +#define SENSOR_TYPE_FANSPEED 2 +#define SENSOR_TYPE_TEMPERATURE 3 + +static char *sensor_type_prefix[] = +{ + "/unknown", + "/voltage", + "/fanspeed", + "/temperature", + NULL +}; + +typedef struct sensors_labeltypes { + char *label; + int type; +} sensors_labeltypes; + +/* finite list of known labels + * sorted reverse by the length for the same type + * because strncmp must match "temp1" before "temp" + */ +static sensors_labeltypes known_features[] = +{ + { "fan7", SENSOR_TYPE_FANSPEED }, + { "fan6", SENSOR_TYPE_FANSPEED }, + { "fan5", SENSOR_TYPE_FANSPEED }, + { "fan4", SENSOR_TYPE_FANSPEED }, + { "fan3", SENSOR_TYPE_FANSPEED }, + { "fan2", SENSOR_TYPE_FANSPEED }, + { "fan1", SENSOR_TYPE_FANSPEED }, + { "in8", SENSOR_TYPE_VOLTAGE }, + { "in7", SENSOR_TYPE_VOLTAGE }, + { "in6", SENSOR_TYPE_VOLTAGE }, + { "in5", SENSOR_TYPE_VOLTAGE }, + { "in4", SENSOR_TYPE_VOLTAGE }, + { "in3", SENSOR_TYPE_VOLTAGE }, + { "in2", SENSOR_TYPE_VOLTAGE }, + { "in0", SENSOR_TYPE_VOLTAGE }, + { "remote_temp", SENSOR_TYPE_TEMPERATURE }, + { "temp7", SENSOR_TYPE_TEMPERATURE }, + { "temp6", SENSOR_TYPE_TEMPERATURE }, + { "temp5", SENSOR_TYPE_TEMPERATURE }, + { "temp4", SENSOR_TYPE_TEMPERATURE }, + { "temp3", SENSOR_TYPE_TEMPERATURE }, + { "temp2", SENSOR_TYPE_TEMPERATURE }, + { "temp1", SENSOR_TYPE_TEMPERATURE }, + { "temp", SENSOR_TYPE_TEMPERATURE }, + { "Vccp2", SENSOR_TYPE_VOLTAGE }, + { "Vccp1", SENSOR_TYPE_VOLTAGE }, + { "vdd", SENSOR_TYPE_VOLTAGE }, + { "vid4", SENSOR_TYPE_VOLTAGE }, + { "vid3", SENSOR_TYPE_VOLTAGE }, + { "vid2", SENSOR_TYPE_VOLTAGE }, + { "vid1", SENSOR_TYPE_VOLTAGE }, + { "vid", SENSOR_TYPE_VOLTAGE }, + { "vin4", SENSOR_TYPE_VOLTAGE }, + { "vin3", SENSOR_TYPE_VOLTAGE }, + { "vin2", SENSOR_TYPE_VOLTAGE }, + { "vin1", SENSOR_TYPE_VOLTAGE }, + { "voltbatt", SENSOR_TYPE_VOLTAGE }, + { "volt12", SENSOR_TYPE_VOLTAGE }, + { "volt5", SENSOR_TYPE_VOLTAGE }, + { "vrm", SENSOR_TYPE_VOLTAGE }, + { "12V", SENSOR_TYPE_VOLTAGE }, + { "2.5V", SENSOR_TYPE_VOLTAGE }, + { "3.3V", SENSOR_TYPE_VOLTAGE }, + { "5V", SENSOR_TYPE_VOLTAGE }, + { 0, -1 } +}; +/* end new naming */ + +static char *config_keys[] = +{ + "Sensor", + "IgnoreSelected", + "ExtendedSensorNaming", + NULL +}; +static int config_keys_num = 3; + +static char **sensor_list = NULL; +static int sensor_list_num = 0; +/* + * sensor_list_action: + * 0 => default is to collect selected sensors + * 1 => ignore selected sensors + */ +static int sensor_list_action = 0; +/* + * sensor_extended_naming: + * 0 => default is to create chip-feature + * 1 => use new naming scheme chip-bus-address/type-feature + */ +static int sensor_extended_naming = 0; + #ifdef HAVE_LIBSENSORS typedef struct featurelist { const sensors_chip_name *chip; const sensors_feature_data *data; + int type; struct featurelist *next; } featurelist_t; featurelist_t *first_feature = NULL; #endif /* defined (HAVE_LIBSENSORS) */ +static int sensors_config (char *key, char *value) +{ + char **temp; + + if (strcasecmp (key, "Sensor") == 0) + { + temp = (char **) realloc (sensor_list, (sensor_list_num + 1) * sizeof (char *)); + if (temp == NULL) + { + syslog (LOG_EMERG, "Cannot allocate more memory."); + return (1); + } + sensor_list = temp; + + if ((sensor_list[sensor_list_num] = strdup (value)) == NULL) + { + syslog (LOG_EMERG, "Cannot allocate memory."); + return (1); + } + sensor_list_num++; + } + else if (strcasecmp (key, "IgnoreSelected") == 0) + { + if ((strcasecmp (value, "True") == 0) + || (strcasecmp (value, "Yes") == 0) + || (strcasecmp (value, "On") == 0)) + sensor_list_action = 1; + else + sensor_list_action = 0; + } + else if (strcasecmp (key, "ExtendedSensorNaming") == 0) + { + if ((strcasecmp (value, "True") == 0) + || (strcasecmp (value, "Yes") == 0) + || (strcasecmp (value, "On") == 0)) + sensor_extended_naming = 1; + else + sensor_extended_naming = 0; + } + else + { + return (-1); + } + + return (0); +} + +/* + * Check if this feature should be ignored. This is called from + * both, `submit' and `write' to give client and server + * the ability to ignore certain stuff... + */ +static int config_get_ignored (const char *inst) +{ + int i; + + /* If no ignored are given collect all features. */ + if (sensor_list_num < 1) + return (0); + + for (i = 0; i < sensor_list_num; i++) + if (strcasecmp (inst, sensor_list[i]) == 0) + return (sensor_list_action); + return (1 - sensor_list_action); +} + static void collectd_sensors_init (void) { #ifdef HAVE_LIBSENSORS @@ -110,34 +297,45 @@ static void collectd_sensors_init (void) if (data->mapping != SENSORS_NO_MAPPING) continue; - /* Only temperature for now.. */ - if (strncmp (data->name, "temp", 4) - && strncmp (data->name, "fan", 3)) - continue; - - if ((new_feature = (featurelist_t *) malloc (sizeof (featurelist_t))) == NULL) + /* Only known features */ + int i = 0; + while (known_features[i].type >= 0) { - perror ("malloc"); - continue; - } - - /* - syslog (LOG_INFO, "sensors: Adding feature: %s/%s", chip->prefix, data->name); - */ - - new_feature->chip = chip; - new_feature->data = data; - new_feature->next = NULL; - - if (first_feature == NULL) - { - first_feature = new_feature; - last_feature = new_feature; - } - else - { - last_feature->next = new_feature; - last_feature = new_feature; + if(strncmp(data->name, known_features[i].label, strlen(known_features[i].label)) == 0) + { + /* skip ignored in sensors.conf */ + if (sensors_get_ignored(*chip, data->number) == 0) + { + break; + } + + if ((new_feature = (featurelist_t *) malloc (sizeof (featurelist_t))) == NULL) + { + perror ("malloc"); + break; + } + + DBG ("Adding feature: %s/%s/%i", chip->prefix, data->name, known_features[i].type); + new_feature->chip = chip; + new_feature->data = data; + new_feature->type = known_features[i].type; + new_feature->next = NULL; + + if (first_feature == NULL) + { + first_feature = new_feature; + last_feature = new_feature; + } + else + { + last_feature->next = new_feature; + last_feature = new_feature; + } + + /* stop searching known features at first found */ + break; + } + i++; } } } @@ -153,14 +351,37 @@ static void sensors_write (char *host, char *inst, char *val) { char file[BUFSIZE]; int status; + char *typestart; + + /* skip ignored in our config */ + if (config_get_ignored (inst)) + return; - status = snprintf (file, BUFSIZE, filename_format, inst); + /* extended sensor naming */ + if(sensor_extended_naming) + status = snprintf (file, BUFSIZE, sensor_filename_format, inst); + else + status = snprintf (file, BUFSIZE, filename_format, inst); if (status < 1) return; else if (status >= BUFSIZE) return; - rrd_update_file (host, file, val, ds_def, ds_num); + if(sensor_extended_naming) + { + typestart = strrchr(inst, '/'); + if(typestart != NULL) + { + if(strncmp(typestart, sensor_type_prefix[SENSOR_TYPE_VOLTAGE], strlen(sensor_type_prefix[SENSOR_TYPE_VOLTAGE])) == 0) + rrd_update_file (host, file, val, sensor_voltage_ds_def, sensor_voltage_ds_num); + else + rrd_update_file (host, file, val, ds_def, ds_num); + } + else + return; + } + else + rrd_update_file (host, file, val, ds_def, ds_num); } #if SENSORS_HAVE_READ @@ -169,12 +390,17 @@ static void sensors_submit (const char *feat_name, const char *chip_prefix, doub char buf[BUFSIZE]; char inst[BUFSIZE]; - if (snprintf (buf, BUFSIZE, "%u:%.3f", (unsigned int) curtime, value) >= BUFSIZE) + if (snprintf (inst, BUFSIZE, "%s-%s", chip_prefix, feat_name) >= BUFSIZE) return; - if (snprintf (inst, BUFSIZE, "%s-%s", chip_prefix, feat_name) >= BUFSIZE) + /* skip ignored in our config */ + if (config_get_ignored (inst)) + return; + + if (snprintf (buf, BUFSIZE, "%u:%.3f", (unsigned int) curtime, value) >= BUFSIZE) return; + DBG ("%s, %s", inst, buf); plugin_submit (MODULE_NAME, inst, buf); } @@ -182,13 +408,37 @@ static void sensors_read (void) { featurelist_t *feature; double value; + char chip_fullprefix[BUFSIZE]; for (feature = first_feature; feature != NULL; feature = feature->next) { - if (sensors_get_feature (*feature->chip, feature->data->number, &value) < 0) - continue; + if (sensors_get_feature (*feature->chip, feature->data->number, &value) < 0) + continue; + if(sensor_extended_naming) + { + /* full chip name logic borrowed from lm_sensors */ + if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_ISA) + { + if (snprintf (chip_fullprefix, BUFSIZE, "%s-isa-%04x%s", feature->chip->prefix, feature->chip->addr, sensor_type_prefix[feature->type]) >= BUFSIZE) + continue; + } + else if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY) + { + if (snprintf (chip_fullprefix, BUFSIZE, "%s-%s-%04x%s", feature->chip->prefix, feature->chip->busname, feature->chip->addr, sensor_type_prefix[feature->type]) >= BUFSIZE) + continue; + } + else + { + if (snprintf (chip_fullprefix, BUFSIZE, "%s-i2c-%d-%02x%s", feature->chip->prefix, feature->chip->bus, feature->chip->addr, sensor_type_prefix[feature->type]) >= BUFSIZE) + continue; + } + sensors_submit (feature->data->name, (const char *)chip_fullprefix, value); + } + else + { sensors_submit (feature->data->name, feature->chip->prefix, value); + } } } #else @@ -198,6 +448,7 @@ static void sensors_read (void) void module_register (void) { plugin_register (MODULE_NAME, collectd_sensors_init, sensors_read, sensors_write); + cf_register (MODULE_NAME, sensors_config, config_keys, config_keys_num); } #undef BUFSIZE -- 2.11.0