diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
commit | c21c3b0befeb46a51b6bf3758ffa30813bea0ff0 (patch) | |
tree | 9754ff1ca740f6346cf8483ec915d4054bc5da2d /collectors/freeipmi.plugin/freeipmi_plugin.c | |
parent | Adding upstream version 1.43.2. (diff) | |
download | netdata-0d980fd06561f4670f5d8170c5aedd74023e3702.tar.xz netdata-0d980fd06561f4670f5d8170c5aedd74023e3702.zip |
Adding upstream version 1.44.3.upstream/1.44.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | collectors/freeipmi.plugin/freeipmi_plugin.c | 244 |
1 files changed, 215 insertions, 29 deletions
diff --git a/collectors/freeipmi.plugin/freeipmi_plugin.c b/collectors/freeipmi.plugin/freeipmi_plugin.c index 63147d621..6ec9b698b 100644 --- a/collectors/freeipmi.plugin/freeipmi_plugin.c +++ b/collectors/freeipmi.plugin/freeipmi_plugin.c @@ -22,6 +22,10 @@ #include "libnetdata/libnetdata.h" #include "libnetdata/required_dummies.h" +#define FREEIPMI_GLOBAL_FUNCTION_SENSORS() do { \ + fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"ipmi-sensors\" %d \"%s\"\n", 5, "Displays current sensor state and readings"); \ + } while(0) + // component names, based on our patterns #define NETDATA_SENSOR_COMPONENT_MEMORY_MODULE "Memory Module" #define NETDATA_SENSOR_COMPONENT_MEMORY "Memory" @@ -83,6 +87,12 @@ static void netdata_update_ipmi_sel_events_count(struct netdata_ipmi_state *stat /* Communication Configuration - Initialize accordingly */ +static netdata_mutex_t stdout_mutex = NETDATA_MUTEX_INITIALIZER; +static bool function_plugin_should_exit = false; + +int update_every = IPMI_SENSORS_MIN_UPDATE_EVERY; // this is the minimum update frequency +int update_every_sel = IPMI_SEL_MIN_UPDATE_EVERY; // this is the minimum update frequency for SEL events + /* Hostname, NULL for In-band communication, non-null for a hostname */ char *hostname = NULL; @@ -707,6 +717,8 @@ struct netdata_ipmi_state { } updates; }; +struct netdata_ipmi_state state = {0}; + // ---------------------------------------------------------------------------- // excluded record ids maintenance (both for sensor data and state) @@ -1297,6 +1309,7 @@ static size_t send_ipmi_sensor_metrics_to_netdata(struct netdata_ipmi_state *sta int update_every = (int)(state->sensors.freq_ut / USEC_PER_SEC); struct sensor *sn; + netdata_mutex_lock(&stdout_mutex); // generate the CHART/DIMENSION lines, if we have to dfe_start_reentrant(state->sensors.dict, sn) { if(unlikely(!sn->do_metric && !sn->do_state)) @@ -1396,12 +1409,16 @@ static size_t send_ipmi_sensor_metrics_to_netdata(struct netdata_ipmi_state *sta } dfe_done(sn); + netdata_mutex_unlock(&stdout_mutex); + return total_sensors_sent; } static size_t send_ipmi_sel_metrics_to_netdata(struct netdata_ipmi_state *state) { static bool sel_chart_generated = false; + netdata_mutex_lock(&stdout_mutex); + if(likely(state->sel.status == ICS_RUNNING)) { if(unlikely(!sel_chart_generated)) { sel_chart_generated = true; @@ -1422,39 +1439,197 @@ static size_t send_ipmi_sel_metrics_to_netdata(struct netdata_ipmi_state *state) ); } + netdata_mutex_unlock(&stdout_mutex); + return state->sel.events; } // ---------------------------------------------------------------------------- -// main, command line arguments parsing -int main (int argc, char **argv) { - bool netdata_do_sel = IPMI_ENABLE_SEL_BY_DEFAULT; +static const char *get_sensor_state_string(struct sensor *sn) { + switch (sn->sensor_state) { + case IPMI_MONITORING_STATE_NOMINAL: + return "nominal"; + case IPMI_MONITORING_STATE_WARNING: + return "warning"; + case IPMI_MONITORING_STATE_CRITICAL: + return "critical"; + default: + return "unknown"; + } +} - stderror = stderr; - clocks_init(); +static const char *get_sensor_function_priority(struct sensor *sn) { + switch (sn->sensor_state) { + case IPMI_MONITORING_STATE_WARNING: + return "warning"; + case IPMI_MONITORING_STATE_CRITICAL: + return "critical"; + default: + return "normal"; + } +} - int update_every = IPMI_SENSORS_MIN_UPDATE_EVERY; // this is the minimum update frequency - int update_every_sel = IPMI_SEL_MIN_UPDATE_EVERY; // this is the minimum update frequency for SEL events - bool debug = false; +static void freeimi_function_sensors(const char *transaction, char *function __maybe_unused, int timeout __maybe_unused, bool *cancelled __maybe_unused) { + time_t expires = now_realtime_sec() + update_every; - // ------------------------------------------------------------------------ - // initialization of netdata plugin + BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL); + buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS); + buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK); + buffer_json_member_add_string(wb, "type", "table"); + buffer_json_member_add_time_t(wb, "update_every", update_every); + buffer_json_member_add_string(wb, "help", "View IPMI sensor readings and its state"); + buffer_json_member_add_array(wb, "data"); - program_name = "freeipmi.plugin"; + struct sensor *sn; + dfe_start_reentrant(state.sensors.dict, sn) { + if (unlikely(!sn->do_metric && !sn->do_state)) + continue; + + double reading = NAN; + switch (sn->sensor_reading_type) { + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32: + reading = (double)sn->sensor_reading.uint32_value; + break; + case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE: + reading = (double)(sn->sensor_reading.double_value); + break; + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL: + reading = (double)sn->sensor_reading.bool_value; + break; + } - // disable syslog - error_log_syslog = 0; + buffer_json_add_array_item_array(wb); - // set errors flood protection to 100 logs per hour - error_log_errors_per_period = 100; - error_log_throttle_period = 3600; + buffer_json_add_array_item_string(wb, sn->sensor_name); + buffer_json_add_array_item_string(wb, sn->type); + buffer_json_add_array_item_string(wb, sn->component); + buffer_json_add_array_item_double(wb, reading); + buffer_json_add_array_item_string(wb, sn->units); + buffer_json_add_array_item_string(wb, get_sensor_state_string(sn)); - log_set_global_severity_for_external_plugins(); + buffer_json_add_array_item_object(wb); + buffer_json_member_add_string(wb, "severity", get_sensor_function_priority(sn)); + buffer_json_object_close(wb); - // initialize the threads + buffer_json_array_close(wb); + } + dfe_done(sn); + + buffer_json_array_close(wb); // data + buffer_json_member_add_object(wb, "columns"); + { + size_t field_id = 0; + + buffer_rrdf_table_add_field(wb, field_id++, "Sensor", "Sensor Name", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Type", "Sensor Type", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Component", "Sensor Component", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Reading", "Sensor Current Reading", + RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, + 2, NULL, 0, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Units", "Sensor Reading Units", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "State", "Sensor State", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + buffer_rrdf_table_add_field( + wb, field_id++, + "rowOptions", "rowOptions", + RRDF_FIELD_TYPE_NONE, + RRDR_FIELD_VISUAL_ROW_OPTIONS, + RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN, + RRDF_FIELD_SORT_FIXED, + NULL, + RRDF_FIELD_SUMMARY_COUNT, + RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_DUMMY, + NULL); + } + + buffer_json_object_close(wb); // columns + buffer_json_member_add_string(wb, "default_sort_column", "Type"); + + buffer_json_member_add_object(wb, "charts"); + { + buffer_json_member_add_object(wb, "Sensors"); + { + buffer_json_member_add_string(wb, "name", "Sensors"); + buffer_json_member_add_string(wb, "type", "stacked-bar"); + buffer_json_member_add_array(wb, "columns"); + { + buffer_json_add_array_item_string(wb, "Sensor"); + } + buffer_json_array_close(wb); + } + buffer_json_object_close(wb); + } + buffer_json_object_close(wb); // charts + + buffer_json_member_add_array(wb, "default_charts"); + { + buffer_json_add_array_item_array(wb); + buffer_json_add_array_item_string(wb, "Sensors"); + buffer_json_add_array_item_string(wb, "Component"); + buffer_json_array_close(wb); + + buffer_json_add_array_item_array(wb); + buffer_json_add_array_item_string(wb, "Sensors"); + buffer_json_add_array_item_string(wb, "State"); + buffer_json_array_close(wb); + } + buffer_json_array_close(wb); + + buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1); + buffer_json_finalize(wb); + + pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires, wb); + + buffer_free(wb); +} + +// ---------------------------------------------------------------------------- +// main, command line arguments parsing + +static void plugin_exit(int code) { + fflush(stdout); + function_plugin_should_exit = true; + exit(code); +} + +int main (int argc, char **argv) { + clocks_init(); + nd_log_initialize_for_external_plugins("freeipmi.plugin"); netdata_threads_init_for_external_plugins(0); // set the default threads stack size here + bool netdata_do_sel = IPMI_ENABLE_SEL_BY_DEFAULT; + + bool debug = false; + // ------------------------------------------------------------------------ // parse command line parameters @@ -1728,7 +1903,7 @@ int main (int argc, char **argv) { errno = 0; if(freq_s && freq_s < update_every) - collector_error("%s(): update frequency %d seconds is too small for IPMI. Using %d.", + collector_info("%s(): update frequency %d seconds is too small for IPMI. Using %d.", __FUNCTION__, freq_s, update_every); update_every = freq_s = MAX(freq_s, update_every); @@ -1801,16 +1976,17 @@ int main (int argc, char **argv) { heartbeat_t hb; heartbeat_init(&hb); + for(iteration = 0; 1 ; iteration++) { usec_t dt = heartbeat_next(&hb, step); if (!tty) { + netdata_mutex_lock(&stdout_mutex); fprintf(stdout, "\n"); // keepalive to avoid parser read timeout (2 minutes) during ipmi_detect_speed_secs() fflush(stdout); + netdata_mutex_unlock(&stdout_mutex); } - struct netdata_ipmi_state state = {0 }; - spinlock_lock(&sensors_data.spinlock); state.sensors = sensors_data.state.sensors; spinlock_unlock(&sensors_data.spinlock); @@ -1827,8 +2003,7 @@ int main (int argc, char **argv) { __FUNCTION__, (size_t)((now_monotonic_usec() - state.sensors.last_iteration_ut) / USEC_PER_SEC)); fprintf(stdout, "EXIT\n"); - fflush(stdout); - exit(0); + plugin_exit(0); } break; @@ -1838,14 +2013,12 @@ int main (int argc, char **argv) { case ICS_INIT_FAILED: collector_error("%s(): sensors failed to initialize. Calling DISABLE.", __FUNCTION__); fprintf(stdout, "DISABLE\n"); - fflush(stdout); - exit(0); + plugin_exit(0); case ICS_FAILED: collector_error("%s(): sensors fails repeatedly to collect metrics. Exiting to restart.", __FUNCTION__); fprintf(stdout, "EXIT\n"); - fflush(stdout); - exit(0); + plugin_exit(0); } if(netdata_do_sel) { @@ -1865,6 +2038,16 @@ int main (int argc, char **argv) { if(unlikely(debug)) fprintf(stderr, "%s: calling send_ipmi_sensor_metrics_to_netdata()\n", program_name); + static bool add_func_sensors = true; + if (add_func_sensors) { + add_func_sensors = false; + struct functions_evloop_globals *wg = + functions_evloop_init(1, "FREEIPMI", &stdout_mutex, &function_plugin_should_exit); + functions_evloop_add_function( + wg, "ipmi-sensors", freeimi_function_sensors, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT); + FREEIPMI_GLOBAL_FUNCTION_SENSORS(); + } + state.updates.now_ut = now_monotonic_usec(); send_ipmi_sensor_metrics_to_netdata(&state); @@ -1880,6 +2063,8 @@ int main (int argc, char **argv) { , state.sensors.collected ); + netdata_mutex_lock(&stdout_mutex); + if (!global_chart_created) { global_chart_created = true; @@ -1899,10 +2084,11 @@ int main (int argc, char **argv) { if (now_monotonic_sec() - started_t > IPMI_RESTART_EVERY_SECONDS) { collector_info("%s(): reached my lifetime expectancy. Exiting to restart.", __FUNCTION__); fprintf(stdout, "EXIT\n"); - fflush(stdout); - exit(0); + plugin_exit(0); } fflush(stdout); + + netdata_mutex_unlock(&stdout_mutex); } } |