]> arthur.barton.de Git - netdata.git/blobdiff - src/freeipmi_plugin.c
Merge pull request #1968 from ktsaou/master
[netdata.git] / src / freeipmi_plugin.c
index d5f6ea951565cf8a919c99aff99679378b7b0fd0..4459de7cac48845dce507b700380af8835299c2b 100644 (file)
@@ -1,31 +1,20 @@
-/*****************************************************************************\
- *  $Id: ipmimonitoring-sensors.c,v 1.51 2016/11/02 23:46:24 chu11 Exp $
- *  $Id: ipmimonitoring-sel.c,v 1.51 2016/11/02 23:46:24 chu11 Exp $
- *****************************************************************************
+/*
+ *  netdata freeipmi.plugin
+ *  Copyright (C) 2017 Costa Tsaousis
+ *  GPL v3+
+ *
+ *  Based on:
+ *  ipmimonitoring-sensors.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
+ *  ipmimonitoring-sel.c,v 1.51 2016/11/02 23:46:24 chu11 Exp
+ *
  *  Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
  *  Copyright (C) 2006-2007 The Regents of the University of California.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Albert Chu <chu11@llnl.gov>
  *  UCRL-CODE-222073
- *
- *  This file is part of Ipmimonitoring, an IPMI sensor monitoring
- *  library.  For details, see http://www.llnl.gov/linux/.
- *
- *  Ipmimonitoring 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 3 of the License, or (at your
- *  option) any later version.
- *
- *  Ipmimonitoring 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 Ipmimonitoring.  If not, see <http://www.gnu.org/licenses/>.
-\*****************************************************************************/
+ */
 
-#include "config.h"
+#include "common.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 char *hostname = NULL;
 
 /* In-band Communication Configuration */
-int driver_type = IPMI_MONITORING_DRIVER_TYPE_KCS; /* or -1 for default */
+int driver_type = -1; // IPMI_MONITORING_DRIVER_TYPE_KCS; /* or -1 for default */
 int disable_auto_probe = 0;     /* probe for in-band device */
 unsigned int driver_address = 0; /* not used if probing */
 unsigned int register_spacing = 0; /* not used if probing */
 char *driver_device = NULL;     /* not used if probing */
 
 /* Out-of-band Communication Configuration */
-int protocol_version = IPMI_MONITORING_PROTOCOL_VERSION_1_5; /* or -1 for default */
+int protocol_version = -1; //IPMI_MONITORING_PROTOCOL_VERSION_1_5; /* or -1 for default */
 char *username = "foousername";
 char *password = "foopassword";
 unsigned char *k_g = NULL;
 unsigned int k_g_len = 0;
-int privilege_level = IPMI_MONITORING_PRIVILEGE_LEVEL_USER; /* or -1 for default */
-int authentication_type = IPMI_MONITORING_AUTHENTICATION_TYPE_MD5; /* or -1 for default */
+int privilege_level = -1; // IPMI_MONITORING_PRIVILEGE_LEVEL_USER; /* or -1 for default */
+int authentication_type = -1; // IPMI_MONITORING_AUTHENTICATION_TYPE_MD5; /* or -1 for default */
 int cipher_suite_id = 0;        /* or -1 for default */
 int session_timeout = 0;        /* 0 for default */
 int retransmission_timeout = 0; /* 0 for default */
@@ -255,10 +244,14 @@ static int debug = 0;
 
 static int netdata_update_every = 5;
 static int netdata_priority = 90000;
+static int netdata_do_sel = 1;
 
 static size_t netdata_sensors_updated = 0;
 static size_t netdata_sensors_collected = 0;
 static size_t netdata_sel_events = 0;
+static size_t netdata_sensors_states_nominal = 0;
+static size_t netdata_sensors_states_warning = 0;
+static size_t netdata_sensors_states_critical = 0;
 
 struct sensor {
     int record_id;
@@ -290,6 +283,10 @@ static void netdata_mark_as_not_updated() {
     netdata_sensors_updated = 0;
     netdata_sensors_collected = 0;
     netdata_sel_events = 0;
+
+    netdata_sensors_states_nominal = 0;
+    netdata_sensors_states_warning = 0;
+    netdata_sensors_states_critical = 0;
 }
 
 static void send_chart_to_netdata_for_units(int units) {
@@ -298,49 +295,49 @@ static void send_chart_to_netdata_for_units(int units) {
     switch(units) {
         case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
             printf("CHART ipmi.temperatures_c '' 'System Celcius Temperatures read by IPMI' 'Celcius' 'temperatures' 'ipmi.temperatures_c' 'line' %d %d\n"
-                   , netdata_priority
+                   , netdata_priority + 10
                    , netdata_update_every
             );
             break;
 
         case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
             printf("CHART ipmi.temperatures_f '' 'System Fahrenheit Temperatures read by IPMI' 'Fahrenheit' 'temperatures' 'ipmi.temperatures_f' 'line' %d %d\n"
-                   , netdata_priority
+                   , netdata_priority + 11
                    , netdata_update_every
             );
             break;
 
         case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
             printf("CHART ipmi.volts '' 'System Voltages read by IPMI' 'Volts' 'voltages' 'ipmi.voltages' 'line' %d %d\n"
-                   , netdata_priority
+                   , netdata_priority + 12
                    , netdata_update_every
             );
             break;
 
         case IPMI_MONITORING_SENSOR_UNITS_AMPS:
             printf("CHART ipmi.amps '' 'System Current read by IPMI' 'Amps' 'current' 'ipmi.amps' 'line' %d %d\n"
-                   , netdata_priority
+                   , netdata_priority + 13
                    , netdata_update_every
             );
             break;
 
         case IPMI_MONITORING_SENSOR_UNITS_RPM:
             printf("CHART ipmi.rpm '' 'System Fans read by IPMI' 'RPM' 'fans' 'ipmi.rpm' 'line' %d %d\n"
-                   , netdata_priority
+                   , netdata_priority + 14
                    , netdata_update_every
             );
             break;
 
         case IPMI_MONITORING_SENSOR_UNITS_WATTS:
             printf("CHART ipmi.watts '' 'System Power read by IPMI' 'Watts' 'power' 'ipmi.watts' 'line' %d %d\n"
-                   , netdata_priority
+                   , netdata_priority + 5
                    , netdata_update_every
             );
             break;
 
         case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
             printf("CHART ipmi.percent '' 'System Metrics read by IPMI' '%%' 'other' 'ipmi.percent' 'line' %d %d\n"
-                   , netdata_priority
+                   , netdata_priority + 15
                    , netdata_update_every
             );
             break;
@@ -470,23 +467,53 @@ static void send_metrics_to_netdata_for_units(int units) {
 }
 
 static void send_metrics_to_netdata() {
-    static int sel_chart_generated = 0;
+    static int sel_chart_generated = 0, sensors_states_chart_generated = 0;
     struct sensor *sn;
 
-    if(!sel_chart_generated) {
-        printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' 'ipmi.sel' 'area' %d %d\n"
-               , netdata_priority
+    if(netdata_do_sel && !sel_chart_generated) {
+        sel_chart_generated = 1;
+        printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' ipmi.sel area %d %d\n"
+               , netdata_priority + 2
                , netdata_update_every
         );
         printf("DIMENSION events '' absolute 1 1\n");
     }
 
+    if(!sensors_states_chart_generated) {
+        sensors_states_chart_generated = 1;
+        printf("CHART ipmi.sensors_states '' 'IPMI Sensors State' 'sensors' 'states' ipmi.sensors_states line %d %d\n"
+               , netdata_priority + 1
+               , netdata_update_every
+        );
+        printf("DIMENSION nominal '' absolute 1 1\n");
+        printf("DIMENSION critical '' absolute 1 1\n");
+        printf("DIMENSION warning '' absolute 1 1\n");
+    }
+
     // generate the CHART/DIMENSION lines, if we have to
     for(sn = sensors_root; sn; sn = sn->next)
         if(sn->updated && !sn->exposed && !sn->ignore)
             send_chart_to_netdata_for_units(sn->sensor_units);
 
-    printf("BEGIN ipmi.events\nSET events = %zu\nEND\n", netdata_sel_events);
+    if(netdata_do_sel) {
+        printf(
+                "BEGIN ipmi.events\n"
+                "SET events = %zu\n"
+                "END\n"
+                , netdata_sel_events
+        );
+    }
+
+    printf(
+           "BEGIN ipmi.sensors_states\n"
+           "SET nominal = %zu\n"
+           "SET warning = %zu\n"
+           "SET critical = %zu\n"
+           "END\n"
+           , netdata_sensors_states_nominal
+           , netdata_sensors_states_warning
+           , netdata_sensors_states_critical
+    );
 
     // send metrics to netdata
     for(sn = sensors_root; sn; sn = sn->next)
@@ -521,8 +548,7 @@ static void netdata_get_sensor(
 
         sn = calloc(1, sizeof(struct sensor));
         if(!sn) {
-            fprintf(stderr, "freeipmi.plugin: cannot allocate %zu bytes of memory.", sizeof(struct sensor));
-            exit(1);
+            fatal("cannot allocate %zu bytes of memory.", sizeof(struct sensor));
         }
 
         sn->record_id = record_id;
@@ -533,8 +559,7 @@ static void netdata_get_sensor(
         sn->sensor_reading_type = sensor_reading_type;
         sn->sensor_name = strdup(sensor_name);
         if(!sn->sensor_name) {
-            fprintf(stderr, "freeipmi.plugin: cannot allocate %zu bytes of memory.", strlen(sensor_name));
-            exit(1);
+            fatal("cannot allocate %zu bytes of memory.", strlen(sensor_name));
         }
 
         sn->next = sensors_root;
@@ -565,14 +590,22 @@ static void netdata_get_sensor(
             break;
     }
 
-/*    switch(sensor_state) {
+    switch(sensor_state) {
         case IPMI_MONITORING_STATE_NOMINAL:
+            netdata_sensors_states_nominal++;
+            break;
+
         case IPMI_MONITORING_STATE_WARNING:
+            netdata_sensors_states_warning++;
+            break;
+
         case IPMI_MONITORING_STATE_CRITICAL:
+            netdata_sensors_states_critical++;
+            break;
+
         default:
             break;
     }
-*/
 }
 
 static void netdata_get_sel(
@@ -588,33 +621,14 @@ static void netdata_get_sel(
 }
 
 
-static unsigned long long now_realtime_usec() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return tv.tv_sec * 1000000ULL + tv.tv_usec;
+void netdata_cleanup_and_exit(int ret) {
+    exit(ret);
 }
 
 // END NETDATA CODE
 // ----------------------------------------------------------------------------
 
 
-/* This is an example of how to use the libipmimonitoring library to
- * read and monitor sensors.
- *
- * At the top of this file, you'll find a number of variables for
- * configuration of IPMI communication and what sensors you are
- * interested in monitoring.  Those variables are used in the
- * libipmimonitoring calls below.
- *
- * Hopefully this example will be sufficient to help anyone program
- * IPMI monitoring software for their environment.
- *
- * To compile, linking against the library should be sufficient for
- * most environments.  e.g.
- *
- * gcc -o freeipmi.plugin freeipmi_plugin.c -lipmimonitoring
- */
-
 static int
 _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
 {
@@ -624,9 +638,8 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
     int sensor_count;
     int rv = -1;
 
-    if (!(ctx = ipmi_monitoring_ctx_create ()))
-    {
-        perror ("ipmi_monitoring_ctx_create:");
+    if (!(ctx = ipmi_monitoring_ctx_create ())) {
+        error("ipmi_monitoring_ctx_create()");
         goto cleanup;
     }
 
@@ -635,8 +648,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
         if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
                 sdr_cache_directory) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_ctx_sdr_cache_directory: %s\n",
+            error("ipmi_monitoring_ctx_sdr_cache_directory(): %s\n",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -648,8 +660,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
         if (ipmi_monitoring_ctx_sensor_config_file (ctx,
                 sensor_config_file) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_ctx_sensor_config_file: %s\n",
+            error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -658,8 +669,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
     {
         if (ipmi_monitoring_ctx_sensor_config_file (ctx, NULL) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_ctx_sensor_config_file: %s\n",
+            error( "ipmi_monitoring_ctx_sensor_config_file(): %s\n",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -705,8 +715,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
                 NULL,
                 NULL)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_readings_by_record_id: %s\n",
+            error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -722,8 +731,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
                 NULL,
                 NULL)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_readings_by_record_id: %s\n",
+            error( "ipmi_monitoring_sensor_readings_by_record_id(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -739,8 +747,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
                 NULL,
                 NULL)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_readings_by_sensor_type: %s\n",
+            error( "ipmi_monitoring_sensor_readings_by_sensor_type(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -777,48 +784,42 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
         if ((record_id = ipmi_monitoring_sensor_read_record_id (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_record_id: %s\n",
+            error( "ipmi_monitoring_sensor_read_record_id(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if ((sensor_number = ipmi_monitoring_sensor_read_sensor_number (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_number: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_number(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_type: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_type(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if (!(sensor_name = ipmi_monitoring_sensor_read_sensor_name (ctx)))
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_name: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_name(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_state: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_state(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if ((sensor_units = ipmi_monitoring_sensor_read_sensor_units (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_units: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_units(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -826,23 +827,21 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
 #ifdef NETDATA_COMMENTED
         if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_bitmask_type: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_bitmask_type(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
         if ((sensor_bitmask = ipmi_monitoring_sensor_read_sensor_bitmask (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_bitmask: %s\n",
+            error(
+                   "ipmi_monitoring_sensor_read_sensor_bitmask(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if (!(sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (ctx)))
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_bitmask_strings: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_bitmask_strings(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -850,8 +849,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
         if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_sensor_reading_type: %s\n",
+            error( "ipmi_monitoring_sensor_read_sensor_reading_type(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -861,8 +859,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
 #ifdef NETDATA_COMMENTED
         if ((event_reading_type_code = ipmi_monitoring_sensor_read_event_reading_type_code (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sensor_read_event_reading_type_code: %s\n",
+            error( "ipmi_monitoring_sensor_read_event_reading_type_code(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -885,7 +882,7 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
         sensor_type_str = _get_sensor_type_string (sensor_type);
 
-        printf ("%u, %s, %u, %s",
+        printf ("%d, %s, %d, %s",
                 record_id,
                 sensor_name,
                 sensor_number,
@@ -985,25 +982,6 @@ _ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
 }
 
 
-/* This is an example of how to use the libipmimonitoring library to
- * read and monitor the SEL.
- *
- * At the top of this file, you'll find a number of variables for
- * configuration of IPMI communication and what SEL records you are
- * interested in monitoring.  Those variables are used in the
- * libipmimonitoring calls below.
- *
- * Hopefully this example will be sufficient to help anyone program
- * IPMI monitoring software for their environment.
- *
- * To compile, linking against the library should be sufficient for
- * most environments.  e.g.
- *
- * gcc -o ipmimonitoring-sel ipmimonitoring-sel.c -lipmimonitoring
- */
-
-/* Communication Configuration - Initialize accordingly */
-
 static int
 _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
 {
@@ -1015,7 +993,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
     if (!(ctx = ipmi_monitoring_ctx_create ()))
     {
-        perror ("ipmi_monitoring_ctx_create:");
+        error("ipmi_monitoring_ctx_create()");
         goto cleanup;
     }
 
@@ -1024,8 +1002,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
         if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
                 sdr_cache_directory) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_ctx_sdr_cache_directory: %s\n",
+            error( "ipmi_monitoring_ctx_sdr_cache_directory(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1037,8 +1014,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
         if (ipmi_monitoring_ctx_sel_config_file (ctx,
                 sel_config_file) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_ctx_sel_config_file: %s\n",
+            error( "ipmi_monitoring_ctx_sel_config_file(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1047,8 +1023,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
     {
         if (ipmi_monitoring_ctx_sel_config_file (ctx, NULL) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_ctx_sel_config_file: %s\n",
+            error( "ipmi_monitoring_ctx_sel_config_file(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1079,8 +1054,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
                 NULL,
                 NULL)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_by_record_id: %s\n",
+            error( "ipmi_monitoring_sel_by_record_id(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1096,8 +1070,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
                 NULL,
                 NULL)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_by_sensor_type: %s\n",
+            error( "ipmi_monitoring_sel_by_sensor_type(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1114,8 +1087,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
                 NULL,
                 NULL)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_by_sensor_type: %s\n",
+            error( "ipmi_monitoring_sel_by_sensor_type(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1131,8 +1103,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
                 NULL,
                 NULL)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_by_record_id: %s\n",
+            error( "ipmi_monitoring_sel_by_record_id(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1172,32 +1143,28 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
         if ((record_id = ipmi_monitoring_sel_read_record_id (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_read_record_id: %s\n",
+            error( "ipmi_monitoring_sel_read_record_id(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if ((record_type = ipmi_monitoring_sel_read_record_type (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_read_record_type: %s\n",
+            error( "ipmi_monitoring_sel_read_record_type(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if ((record_type_class = ipmi_monitoring_sel_read_record_type_class (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_read_record_type_class: %s\n",
+            error( "ipmi_monitoring_sel_read_record_type_class(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
 
         if ((sel_state = ipmi_monitoring_sel_read_sel_state (ctx)) < 0)
         {
-            fprintf (stderr,
-                    "ipmi_monitoring_sel_read_sel_state: %s\n",
+            error( "ipmi_monitoring_sel_read_sel_state(): %s",
                     ipmi_monitoring_ctx_errormsg (ctx));
             goto cleanup;
         }
@@ -1218,7 +1185,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
         else
             sel_state_str = "N/A";
 
-        printf ("%u, %u, %s",
+        printf ("%d, %d, %s",
                 record_id,
                 record_type,
                 sel_state_str);
@@ -1229,8 +1196,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
             if (ipmi_monitoring_sel_read_timestamp (ctx, &timestamp) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_timestamp: %s\n",
+                error( "ipmi_monitoring_sel_read_timestamp(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
@@ -1259,40 +1225,35 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
             if (!(sensor_name = ipmi_monitoring_sel_read_sensor_name (ctx)))
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_sensor_name: %s\n",
+                error( "ipmi_monitoring_sel_read_sensor_name(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
 
             if ((sensor_type = ipmi_monitoring_sel_read_sensor_type (ctx)) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_sensor_type: %s\n",
+                error( "ipmi_monitoring_sel_read_sensor_type(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
 
             if ((sensor_number = ipmi_monitoring_sel_read_sensor_number (ctx)) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_sensor_number: %s\n",
+                error( "ipmi_monitoring_sel_read_sensor_number(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
 
             if ((event_direction = ipmi_monitoring_sel_read_event_direction (ctx)) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_event_direction: %s\n",
+                error( "ipmi_monitoring_sel_read_event_direction(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
 
             if ((event_type_code = ipmi_monitoring_sel_read_event_type_code (ctx)) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_event_type_code: %s\n",
+                error( "ipmi_monitoring_sel_read_event_type_code(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
@@ -1302,32 +1263,28 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
                     &event_data2,
                     &event_data3) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_event_data: %s\n",
+                error( "ipmi_monitoring_sel_read_event_data(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
 
             if ((event_offset_type = ipmi_monitoring_sel_read_event_offset_type (ctx)) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_event_offset_type: %s\n",
+                error( "ipmi_monitoring_sel_read_event_offset_type(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
 
             if ((event_offset = ipmi_monitoring_sel_read_event_offset (ctx)) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_event_offset: %s\n",
+                error( "ipmi_monitoring_sel_read_event_offset(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
 
             if (!(event_offset_string = ipmi_monitoring_sel_read_event_offset_string (ctx)))
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_event_offset_string: %s\n",
+                error( "ipmi_monitoring_sel_read_event_offset_string(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
@@ -1342,7 +1299,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
             else
                 event_direction_str = "Deassertion";
 
-            printf (", %s, %s, %u, %s, %Xh, %Xh-%Xh-%Xh",
+            printf (", %s, %s, %d, %s, %Xh, %Xh-%Xh-%Xh",
                     sensor_name,
                     sensor_type_str,
                     sensor_number,
@@ -1369,8 +1326,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
             {
                 if ((manufacturer_id = ipmi_monitoring_sel_read_manufacturer_id (ctx)) < 0)
                 {
-                    fprintf (stderr,
-                            "ipmi_monitoring_sel_read_manufacturer_id: %s\n",
+                    error( "ipmi_monitoring_sel_read_manufacturer_id(): %s",
                             ipmi_monitoring_ctx_errormsg (ctx));
                     goto cleanup;
                 }
@@ -1380,8 +1336,7 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
 
             if ((oem_data_len = ipmi_monitoring_sel_read_oem_data (ctx, oem_data, 1024)) < 0)
             {
-                fprintf (stderr,
-                        "ipmi_monitoring_sel_read_oem_data: %s\n",
+                error( "ipmi_monitoring_sel_read_oem_data(): %s",
                         ipmi_monitoring_ctx_errormsg (ctx));
                 goto cleanup;
             }
@@ -1409,9 +1364,13 @@ _ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
 // MAIN PROGRAM FOR NETDATA PLUGIN
 
 int ipmi_collect_data(struct ipmi_monitoring_ipmi_config *ipmi_config) {
+    errno = 0;
 
     if (_ipmimonitoring_sensors(ipmi_config) < 0) return -1;
-    if (_ipmimonitoring_sel    (ipmi_config) < 0) return -2;
+
+    if(netdata_do_sel) {
+        if(_ipmimonitoring_sel(ipmi_config) < 0) return -2;
+    }
 
     return 0;
 }
@@ -1425,10 +1384,9 @@ int ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config) {
 
         // measure the time a data collection needs
         unsigned long long start = now_realtime_usec();
-        if(ipmi_collect_data(ipmi_config) < 0) {
-            fprintf(stderr, "freeipmi.plugin: data collection failed.\n");
-            exit(1);
-        }
+        if(ipmi_collect_data(ipmi_config) < 0)
+            fatal("freeipmi.plugin: data collection failed.");
+
         unsigned long long end = now_realtime_usec();
 
         if(debug) fprintf(stderr, "freeipmi.plugin: data collection speed was %llu usec\n", end - start);
@@ -1438,19 +1396,32 @@ int ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config) {
 
         // wait the same time
         // to avoid flooding the IPMI processor with requests
-        usleep(end - start);
+        sleep_usec(end - start);
     }
 
-    // so, we assume it needed 3x the time
+    // so, we assume it needed 2x the time
     // we find the average in microseconds
     // and we round-up to the closest second
 
-    return (( total * 3 / checks / 1000000 ) + 1);
+    return (( total * 2 / checks / 1000000 ) + 1);
 }
 
 int main (int argc, char **argv) {
-    struct ipmi_monitoring_ipmi_config ipmi_config;
 
+    // ------------------------------------------------------------------------
+    // initialization of netdata plugin
+
+    program_name = "freeipmi.plugin";
+
+    // disable syslog
+    error_log_syslog = 0;
+
+    // set errors flood protection to 100 logs per hour
+    error_log_errors_per_period = 100;
+    error_log_throttle_period = 3600;
+
+
+    // ------------------------------------------------------------------------
     // parse command line parameters
 
     int i, freq = 0;
@@ -1463,90 +1434,188 @@ int main (int argc, char **argv) {
             }
         }
 
-        if(strcmp("debug", argv[i]) == 0) {
+        if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
+            printf("freeipmi.plugin %s\n", VERSION);
+            exit(0);
+        }
+        else if(strcmp("debug", argv[i]) == 0) {
             debug = 1;
             continue;
         }
+        else if(strcmp("sel", argv[i]) == 0) {
+            netdata_do_sel = 1;
+            continue;
+        }
+        else if(strcmp("no-sel", argv[i]) == 0) {
+            netdata_do_sel = 0;
+            continue;
+        }
+        else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
+            fprintf(stderr,
+                    "\n"
+                    " netdata freeipmi.plugin %s\n"
+                    " Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
+                    " Released under GNU General Public License v3 or later.\n"
+                    " All rights reserved.\n"
+                    "\n"
+                    " This program is a data collector plugin for netdata.\n"
+                    "\n"
+                    " Available command line options:\n"
+                    "\n"
+                    "  SECONDS                 data collection frequency\n"
+                    "                          minimum: %d\n"
+                    "\n"
+                    "  debug                   enable verbose output\n"
+                    "                          default: disabled\n"
+                    "\n"
+                    "  sel\n"
+                    "  no-sel                  enable/disable SEL collection\n"
+                    "                          default: %s\n"
+                    "\n"
+                    "  hostname HOST\n"
+                    "  username USER\n"
+                    "  password PASS           connect to remote IPMI host\n"
+                    "                          default: local IPMI processor\n"
+                    "\n"
+                    "  sdr-cache-dir PATH      directory for SDR cache files\n"
+                    "                          default: %s\n"
+                    "\n"
+                    "  sensor-config-file FILE filename to read sensor configuration\n"
+                    "                          default: %s\n"
+                    "\n"
+                    "  -v\n"
+                    "  -V\n"
+                    "  version                 print version and exit\n"
+                    "\n"
+                    " Linux kernel module for IPMI is CPU hungry.\n"
+                    " On Linux run this to lower kipmiN CPU utilization:\n"
+                    " # echo 10 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us\n"
+                    "\n"
+                    " or create: /etc/modprobe.d/ipmi.conf with these contents:\n"
+                    " options ipmi_si kipmid_max_busy_us=10\n"
+                    "\n"
+                    " For more information:\n"
+                    " https://github.com/firehol/netdata/wiki/monitoring-IPMI\n"
+                    "\n"
+                    , VERSION
+                    , netdata_update_every
+                    , netdata_do_sel?"enabled":"disabled"
+                    , sdr_cache_directory?sdr_cache_directory:"system default"
+                    , sensor_config_file?sensor_config_file:"system default"
+            );
+            exit(1);
+        }
+        else if(i < argc && strcmp("hostname", argv[i]) == 0) {
+            hostname = strdupz(argv[++i]);
+            char *s = argv[i];
+            // mask it be hidden from the process tree
+            while(*s) *s++ = 'x';
+            if(debug) fprintf(stderr, "freeipmi.plugin: hostname set to '%s'\n", hostname);
+            continue;
+        }
+        else if(i < argc && strcmp("username", argv[i]) == 0) {
+            username = strdupz(argv[++i]);
+            char *s = argv[i];
+            // mask it be hidden from the process tree
+            while(*s) *s++ = 'x';
+            if(debug) fprintf(stderr, "freeipmi.plugin: username set to '%s'\n", username);
+            continue;
+        }
+        else if(i < argc && strcmp("password", argv[i]) == 0) {
+            password = strdupz(argv[++i]);
+            char *s = argv[i];
+            // mask it be hidden from the process tree
+            while(*s) *s++ = 'x';
+            if(debug) fprintf(stderr, "freeipmi.plugin: password set to '%s'\n", password);
+            continue;
+        }
+        else if(i < argc && strcmp("sdr-cache-dir", argv[i]) == 0) {
+            sdr_cache_directory = argv[++i];
+            if(debug) fprintf(stderr, "freeipmi.plugin: SDR cache directory set to '%s'\n", sdr_cache_directory);
+            continue;
+        }
+        else if(i < argc && strcmp("sensor-config-file", argv[i]) == 0) {
+            sensor_config_file = argv[++i];
+            if(debug) fprintf(stderr, "freeipmi.plugin: sensor config file set to '%s'\n", sensor_config_file);
+            continue;
+        }
 
-        fprintf(stderr, "freeipmi.plugin: ignoring parameter '%s'\n", argv[i]);
+        error("freeipmi.plugin: ignoring parameter '%s'", argv[i]);
     }
 
-    if(freq > 0 && freq < netdata_update_every)
+    if(freq > netdata_update_every)
         netdata_update_every = freq;
 
     else if(freq)
-        fprintf(stderr, "freeipmi.plugin: update frequency %d seconds is too small for IPMI. Using %d", freq, netdata_update_every);
+        error("update frequency %d seconds is too small for IPMI. Using %d.", freq, netdata_update_every);
 
 
+    // ------------------------------------------------------------------------
     // initialize IPMI
 
+    struct ipmi_monitoring_ipmi_config ipmi_config;
+
     if(debug) fprintf(stderr, "freeipmi.plugin: calling _init_ipmi_config()\n");
 
     _init_ipmi_config(&ipmi_config);
 
     if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_monitoring_init()\n");
 
-    if(ipmi_monitoring_init(ipmimonitoring_init_flags, &errnum) < 0) {
-        fprintf(stderr, "ipmi_monitoring_init: %s\n", ipmi_monitoring_ctx_strerror(errnum));
-        exit(1);
-    }
+    if(ipmi_monitoring_init(ipmimonitoring_init_flags, &errnum) < 0)
+        fatal("ipmi_monitoring_init: %s", ipmi_monitoring_ctx_strerror(errnum));
 
     if(debug) fprintf(stderr, "freeipmi.plugin: detecting IPMI minimum update frequency...\n");
     freq = ipmi_detect_speed_secs(&ipmi_config);
     if(debug) fprintf(stderr, "freeipmi.plugin: IPMI minimum update frequency was calculated to %d seconds.\n", freq);
 
     if(netdata_update_every < freq) {
-        fprintf(stderr, "freeipmi.plugin: enforcing minimum data collection frequency, calculated to %d seconds.\n", freq);
+        info("enforcing minimum data collection frequency, calculated to %d seconds.", freq);
         netdata_update_every = freq;
     }
 
+
+    // ------------------------------------------------------------------------
     // the main loop
+
     if(debug) fprintf(stderr, "freeipmi.plugin: starting data collection\n");
 
+    time_t started_t = now_monotonic_sec();
+
     size_t iteration = 0;
-    unsigned long long step = netdata_update_every * 1000000ULL;
-    unsigned long long now = now_realtime_usec();
-    unsigned long long next = now - (now % step) + step;
-    while(1) {
-        unsigned long long last = now;
-        now = now_realtime_usec();
+    usec_t step = netdata_update_every * USEC_PER_SEC;
+
+    heartbeat_t hb;
+    heartbeat_init(&hb);
+    for(iteration = 0; 1 ; iteration++) {
+        usec_t dt = heartbeat_next(&hb, step);
+
         if(debug && iteration)
             fprintf(stderr, "freeipmi.plugin: iteration %zu, dt %llu usec, sensors collected %zu, sensors sent to netdata %zu \n"
                     , iteration
-                    , now - last
+                    , dt
                     , netdata_sensors_collected
                     , netdata_sensors_updated
             );
 
-        while(now < next) {
-            if(debug) fprintf(stderr, "freeipmi.plugin: sleeping for %llu usec\n", next - now);
-            usleep(next - now);
-            now = now_realtime_usec();
-        }
-        next = now - (now % step) + step;
-
         netdata_mark_as_not_updated();
 
         if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_collect_data()\n");
-        if(ipmi_collect_data(&ipmi_config) < 0) {
-            fprintf(stderr, "freeipmi.plugin: data collection failed.\n");
-            exit(1);
-        }
+        if(ipmi_collect_data(&ipmi_config) < 0)
+            fatal("data collection failed.");
 
         if(debug) fprintf(stderr, "freeipmi.plugin: calling send_metrics_to_netdata()\n");
         send_metrics_to_netdata();
         fflush(stdout);
 
-        iteration++;
+        // restart check (14400 seconds)
+        if(now_monotonic_sec() - started_t > 14400) exit(0);
     }
-    exit(0);
 }
 
 #else // !HAVE_FREEIPMI
 
 int main(int argc, char **argv) {
-    fprintf(stderr, "freeipmi.plugin: not compiled.");
-    exit(1);
+    fatal("freeipmi.plugin is not compiled.");
 }
 
-#endif
+#endif // !HAVE_FREEIPMI