extended the badges API to support rendering alarms
Costa Tsaousis committed
Aug 21, 2016 at 20:04 UTC
2b3bb61fb38fba736e20c2a713f1a00ba571047a
4 files changed
+101
-19
src/health.c
+16
@@ -420,6 +420,10 @@ static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
420
421
rc->rrdset = st;
422
423
+ rc->rrdset_next = st->alarms;
424
+ rc->rrdset_prev = NULL;
425
+ st->alarms = rc;
426
+
427
if(rc->update_every < rc->rrdset->update_every) {
428
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);
429
rc->update_every = rc->rrdset->update_every;
@@ -511,6 +515,18 @@ inline void rrdsetcalc_unlink(RRDCALC *rc) {
515
// it will be applied automatically
516
}
517
518
+RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
519
+ RRDCALC *rc;
520
+ uint32_t hash = simple_hash(name);
521
+
522
+ for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
523
+ if(rc->hash == hash && !strcmp(rc->name, name))
524
+ return rc;
525
+ }
526
+
527
+ return NULL;
528
+}
529
+
530
static inline int rrdcalc_exists(RRDHOST *host, const char *name, uint32_t hash) {
531
RRDCALC *rc;
532
src/health.h
+1
@@ -256,6 +256,7 @@ extern void rrddimvar_free(RRDDIMVAR *rs);
256
extern void rrdsetcalc_link_matching(RRDSET *st);
257
extern void rrdsetcalc_unlink(RRDCALC *rc);
258
extern void rrdcalctemplate_link_matching(RRDSET *st);
259
+extern RRDCALC *rrdcalc_find(RRDSET *st, const char *name);
260
261
extern void health_init(void);
262
extern void *health_main(void *ptr);
src/web_client.c
+77
-19
@@ -644,7 +644,8 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
644
, *label_color = NULL
645
, *value_color = NULL
646
, *refresh_str = NULL
647
- , *precision_str = NULL;
647
+ , *precision_str = NULL
648
+ , *alarm = NULL;
649
650
int group = GROUP_AVERAGE;
651
uint32_t options = 0x00000000;
@@ -687,6 +688,7 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
688
else if(!strcmp(name, "divide")) divide_str = value;
689
else if(!strcmp(name, "refresh")) refresh_str = value;
690
else if(!strcmp(name, "precision")) precision_str = value;
691
+ else if(!strcmp(name, "alarm")) alarm = value;
692
}
693
694
if(!chart || !*chart) {
@@ -702,6 +704,16 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
704
goto cleanup;
705
}
706
707
+ RRDCALC *rc = NULL;
708
+ if(alarm) {
709
+ rc = rrdcalc_find(st, alarm);
710
+ if (!rc) {
711
+ buffer_svg(w->response.data, "alarm not found", 0, "", NULL, NULL, 1, -1);
712
+ ret = 200;
713
+ goto cleanup;
714
+ }
715
+ }
716
+
717
long long multiply = (multiply_str && *multiply_str )?atol(multiply_str):1;
718
long long divide = (divide_str && *divide_str )?atol(divide_str):1;
719
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) {
727
int refresh = 0;
728
if(refresh_str && *refresh_str) {
729
if(!strcmp(refresh_str, "auto")) {
718
- if(options & RRDR_OPTION_NOT_ALIGNED)
730
+ if(rc) refresh = rc->update_every;
731
+ else if(options & RRDR_OPTION_NOT_ALIGNED)
732
refresh = st->update_every;
733
else {
734
refresh = (before - after);
@@ -729,7 +742,9 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
742
}
743
744
if(!label) {
732
- if(dimensions) {
745
+ if(alarm)
746
+ label = alarm;
747
+ else if(dimensions) {
748
const char *dim = buffer_tostring(dimensions);
749
if(*dim == '|') dim++;
750
label = dim;
@@ -744,9 +759,10 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
759
units = st->units;
760
}
761
747
- 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'"
762
+ 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'"
763
, w->id
764
, chart
765
+ , alarm?alarm:""
766
, (dimensions)?buffer_tostring(dimensions):""
767
, after
768
, before
@@ -755,26 +771,68 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
771
, options
772
);
773
758
- time_t latest_timestamp = 0;
759
- int value_is_null = 1;
760
- calculated_number n = 0;
761
- ret = 500;
774
+ if(rc) {
775
+ calculated_number n = rc->value;
776
+ if(isnan(n) || isinf(n)) n = 0;
777
+
778
+ if (refresh > 0)
779
+ buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
780
+
781
+ if(!value_color) {
782
+ switch(rc->status) {
783
+ case RRDCALC_STATUS_CRITICAL:
784
+ value_color = "red";
785
+ break;
786
+
787
+ case RRDCALC_STATUS_WARNING:
788
+ value_color = "orange";
789
+ break;
790
+
791
+ case RRDCALC_STATUS_CLEAR:
792
+ value_color = "brightgreen";
793
+ break;
794
+
795
+ case RRDCALC_STATUS_UNDEFINED:
796
+ value_color = "lightgrey";
797
+ break;
798
763
- // if the collected value is too old, don't calculate its value
764
- if(rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
765
- ret = rrd2value(st, w->response.data, &n, (dimensions)?buffer_tostring(dimensions):NULL, points, after, before, group, options, &latest_timestamp, &value_is_null);
799
+ case RRDCALC_STATUS_UNINITIALIZED:
800
+ value_color = "#000";
801
+ break;
802
767
- // if the value cannot be calculated, show empty badge
768
- if(ret != 200) {
769
- value_is_null = 1;
770
- n = 0;
803
+ default:
804
+ value_color = "grey";
805
+ break;
806
+ }
807
+ }
808
+
809
+ buffer_svg(w->response.data, label, rc->value * multiply / divide, units, label_color, value_color, 0, precision);
810
ret = 200;
811
}
773
- else if(refresh > 0)
774
- buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
812
+ else {
813
+ time_t latest_timestamp = 0;
814
+ int value_is_null = 1;
815
+ calculated_number n = 0;
816
+ ret = 500;
817
776
- // render the badge
777
- buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null, precision);
818
+ // if the collected value is too old, don't calculate its value
819
+ if (rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
820
+ ret = rrd2value(st, w->response.data, &n, (dimensions) ? buffer_tostring(dimensions) : NULL, points, after,
821
+ before, group, options, &latest_timestamp, &value_is_null);
822
+
823
+ // if the value cannot be calculated, show empty badge
824
+ if (ret != 200) {
825
+ value_is_null = 1;
826
+ n = 0;
827
+ ret = 200;
828
+ }
829
+ else if (refresh > 0)
830
+ buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
831
+
832
+ // render the badge
833
+ buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null,
834
+ precision);
835
+ }
836
837
cleanup:
838
if(dimensions)
web/netdata-swagger.yaml
+7
@@ -157,6 +157,13 @@ paths:
157
format: 'as returned by /charts'
158
allowEmptyValue: false
159
default: system.cpu
160
+ - name: alarm
161
+ in: query
162
+ description: 'the name of an alarm linked to the chart'
163
+ required: false
164
+ type: string
165
+ format: 'any text'
166
+ allowEmptyValue: true
167
- name: dimension
168
in: query
169
description: 'zero, one or more dimension ids, as returned by the /chart call.'