]> arthur.barton.de Git - netdata.git/commitdiff
extended the badges API to support rendering alarms
authorCosta Tsaousis <costa@tsaousis.gr>
Sun, 21 Aug 2016 17:04:28 +0000 (20:04 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Sun, 21 Aug 2016 17:04:28 +0000 (20:04 +0300)
src/health.c
src/health.h
src/web_client.c
web/netdata-swagger.yaml

index bf37b013f62b1f662b93deaa8bf7dc7eab077956..2e5f4aed732155aced5301a55000462795278490 100644 (file)
@@ -420,6 +420,10 @@ static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
 
     rc->rrdset = st;
 
+    rc->rrdset_next = st->alarms;
+    rc->rrdset_prev = NULL;
+    st->alarms = rc;
+
     if(rc->update_every < rc->rrdset->update_every) {
         error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rc->rrdset->id, rc->name, rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
         rc->update_every = rc->rrdset->update_every;
@@ -511,6 +515,18 @@ inline void rrdsetcalc_unlink(RRDCALC *rc) {
     // it will be applied automatically
 }
 
+RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
+    RRDCALC *rc;
+    uint32_t hash = simple_hash(name);
+
+    for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
+        if(rc->hash == hash && !strcmp(rc->name, name))
+            return rc;
+    }
+
+    return NULL;
+}
+
 static inline int rrdcalc_exists(RRDHOST *host, const char *name, uint32_t hash) {
     RRDCALC *rc;
 
index a269699ada048289c1e6f7760c2a6f0f5aa56c8c..5bf6adac51b1d07b7df34d9fcfdbf37b12717058 100644 (file)
@@ -256,6 +256,7 @@ extern void rrddimvar_free(RRDDIMVAR *rs);
 extern void rrdsetcalc_link_matching(RRDSET *st);
 extern void rrdsetcalc_unlink(RRDCALC *rc);
 extern void rrdcalctemplate_link_matching(RRDSET *st);
+extern RRDCALC *rrdcalc_find(RRDSET *st, const char *name);
 
 extern void health_init(void);
 extern void *health_main(void *ptr);
index 6b454b7867ac49b92e4e7cc4861f1b172503bc54..804ea980a9dd8a9ce4cc5643d440edd301df7e62 100644 (file)
@@ -644,7 +644,8 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
             , *label_color = NULL
             , *value_color = NULL
             , *refresh_str = NULL
-            , *precision_str = NULL;
+            , *precision_str = NULL
+            , *alarm = NULL;
 
     int group = GROUP_AVERAGE;
     uint32_t options = 0x00000000;
@@ -687,6 +688,7 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
         else if(!strcmp(name, "divide")) divide_str = value;
         else if(!strcmp(name, "refresh")) refresh_str = value;
         else if(!strcmp(name, "precision")) precision_str = value;
+        else if(!strcmp(name, "alarm")) alarm = value;
     }
 
     if(!chart || !*chart) {
@@ -702,6 +704,16 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
         goto cleanup;
     }
 
+    RRDCALC *rc = NULL;
+    if(alarm) {
+        rc = rrdcalc_find(st, alarm);
+        if (!rc) {
+            buffer_svg(w->response.data, "alarm not found", 0, "", NULL, NULL, 1, -1);
+            ret = 200;
+            goto cleanup;
+        }
+    }
+
     long long multiply  = (multiply_str  && *multiply_str )?atol(multiply_str):1;
     long long divide    = (divide_str    && *divide_str   )?atol(divide_str):1;
     long long before    = (before_str    && *before_str   )?atol(before_str):0;
@@ -715,7 +727,8 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
     int refresh = 0;
     if(refresh_str && *refresh_str) {
         if(!strcmp(refresh_str, "auto")) {
-            if(options & RRDR_OPTION_NOT_ALIGNED)
+            if(rc) refresh = rc->update_every;
+            else if(options & RRDR_OPTION_NOT_ALIGNED)
                 refresh = st->update_every;
             else {
                 refresh = (before - after);
@@ -729,7 +742,9 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
     }
 
     if(!label) {
-        if(dimensions) {
+        if(alarm)
+            label = alarm;
+        else if(dimensions) {
             const char *dim = buffer_tostring(dimensions);
             if(*dim == '|') dim++;
             label = dim;
@@ -744,9 +759,10 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
             units = st->units;
     }
 
-    debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
+    debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
             , w->id
             , chart
+            , alarm?alarm:""
             , (dimensions)?buffer_tostring(dimensions):""
             , after
             , before
@@ -755,26 +771,68 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
             , options
             );
 
-    time_t latest_timestamp = 0;
-    int value_is_null = 1;
-    calculated_number n = 0;
-    ret = 500;
+    if(rc) {
+        calculated_number n = rc->value;
+        if(isnan(n) || isinf(n)) n = 0;
+
+        if (refresh > 0)
+            buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+
+        if(!value_color) {
+            switch(rc->status) {
+                case RRDCALC_STATUS_CRITICAL:
+                    value_color = "red";
+                    break;
+
+                case RRDCALC_STATUS_WARNING:
+                    value_color = "orange";
+                    break;
+
+                case RRDCALC_STATUS_CLEAR:
+                    value_color = "brightgreen";
+                    break;
+
+                case RRDCALC_STATUS_UNDEFINED:
+                    value_color = "lightgrey";
+                    break;
 
-    // if the collected value is too old, don't calculate its value
-    if(rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
-        ret = rrd2value(st, w->response.data, &n, (dimensions)?buffer_tostring(dimensions):NULL, points, after, before, group, options, &latest_timestamp, &value_is_null);
+                case RRDCALC_STATUS_UNINITIALIZED:
+                    value_color = "#000";
+                    break;
 
-    // if the value cannot be calculated, show empty badge
-    if(ret != 200) {
-        value_is_null = 1;
-        n = 0;
+                default:
+                    value_color = "grey";
+                    break;
+            }
+        }
+
+        buffer_svg(w->response.data, label, rc->value * multiply / divide, units, label_color, value_color, 0, precision);
         ret = 200;
     }
-    else if(refresh > 0)
-        buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+    else {
+        time_t latest_timestamp = 0;
+        int value_is_null = 1;
+        calculated_number n = 0;
+        ret = 500;
 
-    // render the badge
-    buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null, precision);
+        // if the collected value is too old, don't calculate its value
+        if (rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
+            ret = rrd2value(st, w->response.data, &n, (dimensions) ? buffer_tostring(dimensions) : NULL, points, after,
+                            before, group, options, &latest_timestamp, &value_is_null);
+
+        // if the value cannot be calculated, show empty badge
+        if (ret != 200) {
+            value_is_null = 1;
+            n = 0;
+            ret = 200;
+        }
+        else if (refresh > 0)
+            buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+
+        // render the badge
+        buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null,
+                   precision);
+    }
 
 cleanup:
     if(dimensions)
index 5d01a73f4cbc84bf69807d6bcc1872414a09cd82..c1049b12d3e7d75a2f7dbf41ae30efb27a2a7fef 100644 (file)
@@ -157,6 +157,13 @@ paths:
           format: 'as returned by /charts'
           allowEmptyValue: false
           default: system.cpu
+        - name: alarm
+          in: query
+          description: 'the name of an alarm linked to the chart'
+          required: false
+          type: string
+          format: 'any text'
+          allowEmptyValue: true
         - name: dimension
           in: query
           description: 'zero, one or more dimension ids, as returned by the /chart call.'