added jsonwrap api option to allow javascript get information about the result set that allows it to refresh charts only when it needs to; dashboard is now optimal regarding server resources
Costa Tsaousis (ktsaou) committed
Dec 3, 2015 at 00:19 UTC
1a7b1af24564e455f0c46f2ec7a3805c3bc9afdd
5 files changed
+597
-274
src/rrd2json.c
+301
-49
@@ -269,9 +269,6 @@ void rrd_stats_all_json(BUFFER *wb)
269
typedef struct rrdresult {
270
RRDSET *st; // the chart this result refers to
271
272
- int group; // how many collected values were grouped for each row
273
- int update_every; // what is the suggested update frequency in seconds
274
-
272
int d; // the number of dimensions
273
int n; // the number of values in the arrays
274
int rows; // the number of rows used
@@ -284,6 +281,15 @@ typedef struct rrdresult {
281
282
int c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
283
284
+ int group; // how many collected values were grouped for each row
285
+ int update_every; // what is the suggested update frequency in seconds
286
+
287
+ calculated_number min;
288
+ calculated_number max;
289
+
290
+ time_t before;
291
+ time_t after;
292
+
293
int has_st_lock; // if st is read locked by us
294
} RRDR;
295
@@ -370,6 +376,153 @@ void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
376
}
377
}
378
379
+void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
380
+{
381
+ switch(format) {
382
+ case DATASOURCE_JSON:
383
+ buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
384
+ break;
385
+
386
+ case DATASOURCE_DATATABLE_JSON:
387
+ buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
388
+ break;
389
+
390
+ case DATASOURCE_DATATABLE_JSONP:
391
+ buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
392
+ break;
393
+
394
+ case DATASOURCE_JSONP:
395
+ buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
396
+ break;
397
+
398
+ case DATASOURCE_SSV:
399
+ buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
400
+ break;
401
+
402
+ case DATASOURCE_CSV:
403
+ buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
404
+ break;
405
+
406
+ case DATASOURCE_TSV:
407
+ buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
408
+ break;
409
+
410
+ case DATASOURCE_HTML:
411
+ buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
412
+ break;
413
+
414
+ case DATASOURCE_JS_ARRAY:
415
+ buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
416
+ break;
417
+
418
+ case DATASOURCE_SSV_COMMA:
419
+ buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
420
+ break;
421
+
422
+ default:
423
+ buffer_strcat(wb, "unknown");
424
+ break;
425
+ }
426
+}
427
+
428
+void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
429
+{
430
+ char kq[2] = "", // key quote
431
+ sq[2] = ""; // string quote
432
+
433
+ if( options & RRDR_OPTION_GOOGLE_JSON ) {
434
+ kq[0] = '\0';
435
+ sq[0] = '\'';
436
+ }
437
+ else {
438
+ kq[0] = '"';
439
+ sq[0] = '"';
440
+ }
441
+
442
+ buffer_sprintf(wb, "{\n"
443
+ " %sid%s: %s%s%s,\n"
444
+ " %sname%s: %s%s%s,\n"
445
+ " %supdate_every%s: %d,\n"
446
+ " %smin%s: "
447
+ , kq, kq, sq, r->st->id, sq
448
+ , kq, kq, sq, r->st->name, sq
449
+ , kq, kq, r->update_every
450
+ , kq, kq);
451
+
452
+ buffer_rrd_value(wb, r->min);
453
+ buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
454
+ buffer_rrd_value(wb, r->max);
455
+ buffer_sprintf(wb, ",\n"
456
+ " %sbefore%s: %u,\n"
457
+ " %safter%s: %u,\n"
458
+ " %sdimension_names%s: ["
459
+ , kq, kq, r->before
460
+ , kq, kq, r->after
461
+ , kq, kq);
462
+
463
+
464
+ long c, i;
465
+ RRDDIM *rd;
466
+ for(c = 0, i = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
467
+ if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
468
+ if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
469
+
470
+ if(i) buffer_strcat(wb, ", ");
471
+ buffer_strcat(wb, sq);
472
+ buffer_strcat(wb, rd->name);
473
+ buffer_strcat(wb, sq);
474
+ i++;
475
+ }
476
+ buffer_sprintf(wb, "],\n"
477
+ " %sdimension_ids%s: ["
478
+ , kq, kq);
479
+
480
+ for(c = 0, i = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
481
+ if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
482
+ if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
483
+
484
+ if(i) buffer_strcat(wb, ", ");
485
+ buffer_strcat(wb, sq);
486
+ buffer_strcat(wb, rd->id);
487
+ buffer_strcat(wb, sq);
488
+ i++;
489
+ }
490
+ buffer_sprintf(wb, "],\n"
491
+ " %sdimensions%s: %d,\n"
492
+ " %spoints%s: %d,\n"
493
+ " %sformat%s: %s"
494
+ , kq, kq, i
495
+ , kq, kq, rrdr_rows(r)
496
+ , kq, kq, sq
497
+ );
498
+
499
+ rrdr_buffer_print_format(wb, format);
500
+
501
+ buffer_sprintf(wb, "%s,\n"
502
+ " %sresult%s: "
503
+ , sq
504
+ , kq, kq
505
+ );
506
+
507
+ if(string_value) buffer_strcat(wb, sq);
508
+}
509
+
510
+void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
511
+{
512
+ if(r) {;}
513
+ if(format) {;}
514
+
515
+ char sq[2] = ""; // string quote
516
+
517
+ if( options & RRDR_OPTION_GOOGLE_JSON )
518
+ sq[0] = '\'';
519
+ else
520
+ sq[0] = '"';
521
+
522
+ if(string_value) buffer_strcat(wb, sq);
523
+ buffer_strcat(wb, "\n}\n");
524
+}
525
+
526
#define JSON_DATES_JS 1
527
#define JSON_DATES_TIMESTAMP 2
528
@@ -414,7 +567,7 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
567
snprintf(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
568
snprintf(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
569
417
- buffer_sprintf(wb, "{\n %supdate_every%s: %d,\n %scols%s:\n [\n", kq, kq, r->update_every, kq, kq, kq, kq);
570
+ buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq, kq, kq);
571
buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
572
buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
573
buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
@@ -449,7 +602,7 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
602
snprintf(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq);
603
snprintf(finish, 100, "\n ]\n}\n");
604
452
- buffer_sprintf(wb, "{\n %supdate_every%s: %d,\n %slabels%s: [", kq, kq, r->update_every, kq, kq);
605
+ buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
606
buffer_sprintf(wb, "%stime%s", sq, sq);
607
}
608
@@ -660,12 +813,12 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
813
}
814
}
815
663
-static void rrdr2ssv(RRDR *r, BUFFER *out, uint32_t options, const char *prefix, const char *separator, const char *suffix)
816
+static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix, const char *separator, const char *suffix)
817
{
818
long c, i;
819
RRDDIM *d;
820
668
- buffer_strcat(out, prefix);
821
+ buffer_strcat(wb, prefix);
822
long start = 0, end = rrdr_rows(r), step = 1;
823
if((options & RRDR_OPTION_REVERSED)) {
824
start = rrdr_rows(r) - 1;
@@ -712,20 +865,20 @@ static void rrdr2ssv(RRDR *r, BUFFER *out, uint32_t options, const char *prefix,
865
}
866
867
if(likely(i != start))
715
- buffer_strcat(out, separator);
868
+ buffer_strcat(wb, separator);
869
870
if(all_null) {
871
if(options & RRDR_OPTION_NULL2ZERO)
719
- buffer_strcat(out, "0");
872
+ buffer_strcat(wb, "0");
873
else
721
- buffer_strcat(out, "null");
874
+ buffer_strcat(wb, "null");
875
}
876
else if(options & RRDR_OPTION_MIN2MAX)
724
- buffer_rrd_value(out, max - min);
877
+ buffer_rrd_value(wb, max - min);
878
else
726
- buffer_rrd_value(out, sum);
879
+ buffer_rrd_value(wb, sum);
880
}
728
- buffer_strcat(out, suffix);
881
+ buffer_strcat(wb, suffix);
882
}
883
884
inline static calculated_number *rrdr_line_values(RRDR *r)
@@ -803,10 +956,11 @@ static RRDR *rrdr_create(RRDSET *st, int n)
956
return NULL;
957
}
958
806
- RRDR *r = calloc(1, sizeof(RRDR));
959
+ RRDR *r = malloc(sizeof(RRDR));
960
if(unlikely(!r)) goto cleanup;
961
962
r->st = st;
963
+ r->has_st_lock = 0;
964
965
rrdr_lock_rrdset(r);
966
@@ -815,21 +969,30 @@ static RRDR *rrdr_create(RRDSET *st, int n)
969
970
r->n = n;
971
818
- r->t = calloc(n, sizeof(time_t));
972
+ r->t = malloc(n * sizeof(time_t));
973
if(unlikely(!r->t)) goto cleanup;
974
821
- r->v = calloc(n * r->d, sizeof(calculated_number));
975
+ r->v = malloc(n * r->d * sizeof(calculated_number));
976
if(unlikely(!r->v)) goto cleanup;
977
824
- r->o = calloc(n * r->d, sizeof(uint8_t));
978
+ r->o = malloc(n * r->d * sizeof(uint8_t));
979
if(unlikely(!r->o)) goto cleanup;
980
827
- r->od = calloc(r->d, sizeof(uint8_t));
981
+ r->od = malloc(r->d * sizeof(uint8_t));
982
if(unlikely(!r->od)) goto cleanup;
983
984
r->c = -1;
985
r->rows = 0;
986
987
+ r->group = 1;
988
+ r->update_every = 1;
989
+
990
+ r->min = 0.0;
991
+ r->max = 0.0;
992
+
993
+ r->before = 0;
994
+ r->after = 0;
995
+
996
return r;
997
998
cleanup:
@@ -1044,7 +1207,13 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
1207
if(unlikely(now > before)) continue;
1208
if(unlikely(now < after)) break;
1209
1047
- if(unlikely(group_count == 0)) group_start_t = now;
1210
+ if(unlikely(group_count == 0)) {
1211
+ group_start_t = now;
1212
+ if(unlikely(!r->before)) {
1213
+ r->before = group_start_t;
1214
+ r->after = group_start_t;
1215
+ }
1216
+ }
1217
group_count++;
1218
1219
if(unlikely(group_count == group)) {
@@ -1086,6 +1255,8 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
1255
if(unlikely(add_this)) {
1256
if(unlikely(!rrdr_line_init(r, group_start_t))) break;
1257
1258
+ r->after = group_start_t;
1259
+
1260
calculated_number *cn = rrdr_line_values(r);
1261
uint8_t *co = rrdr_line_options(r);
1262
@@ -1110,6 +1281,9 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
1281
cn[c] = group_values[c];
1282
}
1283
1284
+ if(cn[c] < r->min) r->min = cn[c];
1285
+ if(cn[c] > r->max) r->max = cn[c];
1286
+
1287
// reset them for the next loop
1288
group_values[c] = 0;
1289
group_counts[c] = 0;
@@ -1121,82 +1295,160 @@ RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int g
1295
add_this = 0;
1296
}
1297
}
1298
+ r->after += group * st->update_every;
1299
1300
rrdr_done(r);
1301
//error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
1302
return r;
1303
}
1304
1130
-int rrd2format(RRDSET *st, BUFFER *out, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp)
1305
+int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp)
1306
{
1132
- RRDR *rrdr = rrd2rrdr(st, points, after, before, group_method);
1133
- if(!rrdr) {
1134
- buffer_strcat(out, "Cannot generate output with these parameters on this chart.");
1307
+ RRDR *r = rrd2rrdr(st, points, after, before, group_method);
1308
+ if(!r) {
1309
+ buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
1310
return 500;
1311
}
1312
1313
if(dimensions)
1139
- rrdr_disable_not_selected_dimensions(rrdr, buffer_tostring(dimensions));
1314
+ rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
1315
1141
- if(latest_timestamp && rrdr_rows(rrdr) > 0)
1142
- *latest_timestamp = rrdr->t[rrdr_rows(rrdr) - 1];
1316
+ if(latest_timestamp && rrdr_rows(r) > 0)
1317
+ *latest_timestamp = r->before;
1318
1319
switch(format) {
1320
case DATASOURCE_SSV:
1146
- out->contenttype = CT_TEXT_PLAIN;
1147
- rrdr2ssv(rrdr, out, options, "", " ", "");
1321
+ if(options & RRDR_OPTION_JSON_WRAP) {
1322
+ wb->contenttype = CT_APPLICATION_JSON;
1323
+ rrdr_json_wrapper_begin(r, wb, format, options, 1);
1324
+ rrdr2ssv(r, wb, options, "", " ", "");
1325
+ rrdr_json_wrapper_end(r, wb, format, options, 1);
1326
+ }
1327
+ else {
1328
+ wb->contenttype = CT_TEXT_PLAIN;
1329
+ rrdr2ssv(r, wb, options, "", " ", "");
1330
+ }
1331
break;
1332
1333
case DATASOURCE_SSV_COMMA:
1151
- out->contenttype = CT_TEXT_PLAIN;
1152
- rrdr2ssv(rrdr, out, options, "", ",", "");
1334
+ if(options & RRDR_OPTION_JSON_WRAP) {
1335
+ wb->contenttype = CT_APPLICATION_JSON;
1336
+ rrdr_json_wrapper_begin(r, wb, format, options, 1);
1337
+ rrdr2ssv(r, wb, options, "", ",", "");
1338
+ rrdr_json_wrapper_end(r, wb, format, options, 1);
1339
+ }
1340
+ else {
1341
+ wb->contenttype = CT_TEXT_PLAIN;
1342
+ rrdr2ssv(r, wb, options, "", ",", "");
1343
+ }
1344
break;
1345
1346
case DATASOURCE_JS_ARRAY:
1156
- out->contenttype = CT_APPLICATION_JSON;
1157
- rrdr2ssv(rrdr, out, options, "[", ",", "]");
1347
+ if(options & RRDR_OPTION_JSON_WRAP) {
1348
+ wb->contenttype = CT_APPLICATION_JSON;
1349
+ rrdr_json_wrapper_begin(r, wb, format, options, 0);
1350
+ rrdr2ssv(r, wb, options, "[", ",", "]");
1351
+ rrdr_json_wrapper_end(r, wb, format, options, 0);
1352
+ }
1353
+ else {
1354
+ wb->contenttype = CT_APPLICATION_JSON;
1355
+ rrdr2ssv(r, wb, options, "[", ",", "]");
1356
+ }
1357
break;
1358
1359
case DATASOURCE_CSV:
1161
- out->contenttype = CT_TEXT_PLAIN;
1162
- rrdr2csv(rrdr, out, options, "", ",", "\r\n");
1360
+ if(options & RRDR_OPTION_JSON_WRAP) {
1361
+ wb->contenttype = CT_APPLICATION_JSON;
1362
+ rrdr_json_wrapper_begin(r, wb, format, options, 1);
1363
+ rrdr2csv(r, wb, options, "", ",", "\\n");
1364
+ rrdr_json_wrapper_end(r, wb, format, options, 1);
1365
+ }
1366
+ else {
1367
+ wb->contenttype = CT_TEXT_PLAIN;
1368
+ rrdr2csv(r, wb, options, "", ",", "\r\n");
1369
+ }
1370
break;
1371
1372
case DATASOURCE_TSV:
1166
- out->contenttype = CT_TEXT_PLAIN;
1167
- rrdr2csv(rrdr, out, options, "", "\t", "\r\n");
1373
+ if(options & RRDR_OPTION_JSON_WRAP) {
1374
+ wb->contenttype = CT_APPLICATION_JSON;
1375
+ rrdr_json_wrapper_begin(r, wb, format, options, 1);
1376
+ rrdr2csv(r, wb, options, "", "\t", "\\n");
1377
+ rrdr_json_wrapper_end(r, wb, format, options, 1);
1378
+ }
1379
+ else {
1380
+ wb->contenttype = CT_TEXT_PLAIN;
1381
+ rrdr2csv(r, wb, options, "", "\t", "\r\n");
1382
+ }
1383
break;
1384
1385
case DATASOURCE_HTML:
1171
- out->contenttype = CT_TEXT_HTML;
1172
- buffer_strcat(out, "<html>\n<center><table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">");
1173
- rrdr2csv(rrdr, out, options, "<tr><td>", "</td><td>", "</td></tr>\n");
1174
- buffer_strcat(out, "</table>\n</center>\n</html>\n");
1386
+ if(options & RRDR_OPTION_JSON_WRAP) {
1387
+ wb->contenttype = CT_APPLICATION_JSON;
1388
+ rrdr_json_wrapper_begin(r, wb, format, options, 1);
1389
+ buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
1390
+ rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n");
1391
+ buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
1392
+ rrdr_json_wrapper_end(r, wb, format, options, 1);
1393
+ }
1394
+ else {
1395
+ wb->contenttype = CT_TEXT_HTML;
1396
+ buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
1397
+ rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n");
1398
+ buffer_strcat(wb, "</table>\n</center>\n</html>\n");
1399
+ }
1400
break;
1401
1402
case DATASOURCE_DATATABLE_JSONP:
1178
- out->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1179
- rrdr2json(rrdr, out, options, 1);
1403
+ wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1404
+
1405
+ if(options & RRDR_OPTION_JSON_WRAP)
1406
+ rrdr_json_wrapper_begin(r, wb, format, options, 0);
1407
+
1408
+ rrdr2json(r, wb, options, 1);
1409
+
1410
+ if(options & RRDR_OPTION_JSON_WRAP)
1411
+ rrdr_json_wrapper_end(r, wb, format, options, 0);
1412
break;
1413
1414
case DATASOURCE_DATATABLE_JSON:
1183
- out->contenttype = CT_APPLICATION_JSON;
1184
- rrdr2json(rrdr, out, options, 1);
1415
+ wb->contenttype = CT_APPLICATION_JSON;
1416
+
1417
+ if(options & RRDR_OPTION_JSON_WRAP)
1418
+ rrdr_json_wrapper_begin(r, wb, format, options, 0);
1419
+
1420
+ rrdr2json(r, wb, options, 1);
1421
+
1422
+ if(options & RRDR_OPTION_JSON_WRAP)
1423
+ rrdr_json_wrapper_end(r, wb, format, options, 0);
1424
break;
1425
1426
case DATASOURCE_JSONP:
1188
- out->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1189
- rrdr2json(rrdr, out, options, 0);
1427
+ wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1428
+ if(options & RRDR_OPTION_JSON_WRAP)
1429
+ rrdr_json_wrapper_begin(r, wb, format, options, 0);
1430
+
1431
+ rrdr2json(r, wb, options, 0);
1432
+
1433
+ if(options & RRDR_OPTION_JSON_WRAP)
1434
+ rrdr_json_wrapper_end(r, wb, format, options, 0);
1435
break;
1436
1437
case DATASOURCE_JSON:
1438
default:
1194
- out->contenttype = CT_APPLICATION_JSON;
1195
- rrdr2json(rrdr, out, options, 0);
1439
+ wb->contenttype = CT_APPLICATION_JSON;
1440
+
1441
+ if(options & RRDR_OPTION_JSON_WRAP)
1442
+ rrdr_json_wrapper_begin(r, wb, format, options, 0);
1443
+
1444
+ rrdr2json(r, wb, options, 0);
1445
+
1446
+ if(options & RRDR_OPTION_JSON_WRAP)
1447
+ rrdr_json_wrapper_end(r, wb, format, options, 0);
1448
break;
1449
}
1450
1199
- rrdr_free(rrdr);
1451
+ rrdr_free(r);
1452
return 200;
1453
}
1454
src/rrd2json.h
+12
@@ -22,6 +22,17 @@ extern char *hostname;
22
#define DATASOURCE_JS_ARRAY 8
23
#define DATASOURCE_SSV_COMMA 9
24
25
+#define DATASOURCE_FORMAT_JSON "json"
26
+#define DATASOURCE_FORMAT_DATATABLE_JSON "datatable"
27
+#define DATASOURCE_FORMAT_DATATABLE_JSONP "datasource"
28
+#define DATASOURCE_FORMAT_JSONP "jsonp"
29
+#define DATASOURCE_FORMAT_SSV "ssv"
30
+#define DATASOURCE_FORMAT_CSV "csv"
31
+#define DATASOURCE_FORMAT_TSV "tsv"
32
+#define DATASOURCE_FORMAT_HTML "html"
33
+#define DATASOURCE_FORMAT_JS_ARRAY "array"
34
+#define DATASOURCE_FORMAT_SSV_COMMA "ssvcomma"
35
+
36
#define GROUP_AVERAGE 0
37
#define GROUP_MAX 1
38
#define GROUP_SUM 2
@@ -35,6 +46,7 @@ extern char *hostname;
46
#define RRDR_OPTION_NULL2ZERO 0x00000040 // do not show nulls, convert them to zeros
47
#define RRDR_OPTION_OBJECTSROWS 0x00000080 // each row of values should be an object, not an array
48
#define RRDR_OPTION_GOOGLE_JSON 0x00000100 // comply with google JSON/JSONP specs
49
+#define RRDR_OPTION_JSON_WRAP 0x00000200 // wrap the response in a JSON header with info about the result
50
51
extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
52
extern void rrd_stats_api_v1_charts(BUFFER *wb);
src/web_client.c
+19
-17
@@ -414,14 +414,16 @@ uint32_t web_client_api_request_v1_data_options(char *o)
414
ret |= RRDR_OPTION_NONZERO;
415
else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
416
ret |= RRDR_OPTION_REVERSED;
417
- else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
418
- ret |= RRDR_OPTION_ABSOLUTE;
417
+ else if(!strcmp(tok, "jsonwrap"))
418
+ ret |= RRDR_OPTION_JSON_WRAP;
419
else if(!strcmp(tok, "min2max"))
420
ret |= RRDR_OPTION_MIN2MAX;
421
- else if(!strcmp(tok, "seconds"))
422
- ret |= RRDR_OPTION_SECONDS;
421
else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
422
ret |= RRDR_OPTION_MILLISECONDS;
423
+ else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
424
+ ret |= RRDR_OPTION_ABSOLUTE;
425
+ else if(!strcmp(tok, "seconds"))
426
+ ret |= RRDR_OPTION_SECONDS;
427
else if(!strcmp(tok, "null2zero"))
428
ret |= RRDR_OPTION_NULL2ZERO;
429
else if(!strcmp(tok, "objectrows"))
@@ -435,39 +437,39 @@ uint32_t web_client_api_request_v1_data_options(char *o)
437
438
int web_client_api_request_v1_data_format(char *name)
439
{
438
- if(!strcmp(name, "datatable"))
440
+ if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
441
return DATASOURCE_DATATABLE_JSON;
442
441
- else if(!strcmp(name, "datasource"))
443
+ else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
444
return DATASOURCE_DATATABLE_JSONP;
445
444
- else if(!strcmp(name, "json"))
446
+ else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
447
return DATASOURCE_JSON;
448
447
- else if(!strcmp(name, "jsonp"))
449
+ else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
450
return DATASOURCE_JSONP;
451
450
- else if(!strcmp(name, "ssv"))
452
+ else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
453
return DATASOURCE_SSV;
454
453
- else if(!strcmp(name, "csv"))
455
+ else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
456
return DATASOURCE_CSV;
457
456
- else if(!strcmp(name, "tsv"))
457
- return DATASOURCE_TSV;
458
-
459
- else if(!strcmp(name, "tsv-excel"))
458
+ else if(!strcmp(name, DATASOURCE_FORMAT_TSV)) // tsv
459
return DATASOURCE_TSV;
460
462
- else if(!strcmp(name, "html"))
461
+ else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
462
return DATASOURCE_HTML;
463
465
- else if(!strcmp(name, "array"))
464
+ else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
465
return DATASOURCE_JS_ARRAY;
466
468
- else if(!strcmp(name, "ssvcomma"))
467
+ else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
468
return DATASOURCE_SSV_COMMA;
469
470
+ else if(!strcmp(name, "tsv-excel"))
471
+ return DATASOURCE_TSV;
472
+
473
return DATASOURCE_JSON;
474
}
475
web/dashboard.html
+16
-16
@@ -17,7 +17,7 @@
17
</head>
18
<body>
19
20
-<h1>NetData Custom Dashboard</h1>
20
+<h1>NetData Custom Dashboard <div data-netdata="system.cpu" data-chart-library="sparkline" data-height="30" data-after="-600" data-sparkline-linecolor="#888"></div></h1>
21
22
This is a template for building custom dashboards. To build a dashboard you just do this:
23
@@ -90,7 +90,7 @@ They also have mouse-hover support.
90
data-chart-library="sparkline"
91
data-width="100%"
92
data-height="30"
93
- data-after="-600"
93
+ data-after="-300"
94
data-dt-element-name="time101"
95
></div>
96
<br/>
@@ -101,7 +101,7 @@ They also have mouse-hover support.
101
data-chart-library="sparkline"
102
data-width="100%"
103
data-height="30"
104
- data-after="-600"
104
+ data-after="-300"
105
data-dt-element-name="time102"
106
></div>
107
<br/>
@@ -112,7 +112,7 @@ They also have mouse-hover support.
112
data-chart-library="sparkline"
113
data-width="100%"
114
data-height="30"
115
- data-after="-600"
115
+ data-after="-300"
116
data-dt-element-name="time103"
117
></div>
118
<br/>
@@ -132,7 +132,7 @@ the total of all dimensions.
132
data-chart-library="peity"
133
data-width="100%"
134
data-height="30"
135
- data-after="-600"
135
+ data-after="-300"
136
data-dt-element-name="time001"
137
></div>
138
<br/>
@@ -143,7 +143,7 @@ the total of all dimensions.
143
data-chart-library="peity"
144
data-width="100%"
145
data-height="30"
146
- data-after="-600"
146
+ data-after="-300"
147
data-dt-element-name="time002"
148
></div>
149
<br/>
@@ -154,7 +154,7 @@ the total of all dimensions.
154
data-chart-library="peity"
155
data-width="100%"
156
data-height="30"
157
- data-after="-600"
157
+ data-after="-300"
158
data-dt-element-name="time003"
159
></div>
160
<br/>
@@ -175,7 +175,7 @@ For the moment zooming is just on the presentation layer (the data do not become
175
data-chart-library="dygraph"
176
data-width="100%"
177
data-height="200"
178
- data-after="-600"
178
+ data-after="-300"
179
data-dt-element-name="time201"
180
></div>
181
<br/>
@@ -186,7 +186,7 @@ For the moment zooming is just on the presentation layer (the data do not become
186
data-chart-library="dygraph"
187
data-width="100%"
188
data-height="200"
189
- data-after="-600"
189
+ data-after="-300"
190
data-dt-element-name="time202"
191
></div>
192
<br/>
@@ -197,7 +197,7 @@ For the moment zooming is just on the presentation layer (the data do not become
197
data-chart-library="dygraph"
198
data-width="100%"
199
data-height="200"
200
- data-after="-600"
200
+ data-after="-300"
201
data-dt-element-name="time203"
202
></div>
203
<br/>
@@ -217,7 +217,7 @@ NetData is a complete Google Visualization API provider.
217
data-chart-library="google"
218
data-width="100%"
219
data-height="200"
220
- data-after="-600"
220
+ data-after="-300"
221
data-dt-element-name="time301"
222
></div>
223
<br/>
@@ -228,7 +228,7 @@ NetData is a complete Google Visualization API provider.
228
data-chart-library="google"
229
data-width="100%"
230
data-height="200"
231
- data-after="-600"
231
+ data-after="-300"
232
data-dt-element-name="time302"
233
></div>
234
<br/>
@@ -239,7 +239,7 @@ NetData is a complete Google Visualization API provider.
239
data-chart-library="google"
240
data-width="100%"
241
data-height="200"
242
- data-after="-600"
242
+ data-after="-300"
243
data-dt-element-name="time303"
244
></div>
245
<br/>
@@ -260,7 +260,7 @@ Unfortunatelly, Morris Charts are veeeeeeeeeeeeeeeery slow! We force them to low
260
data-chart-library="morris"
261
data-width="100%"
262
data-height="200"
263
- data-after="-600"
263
+ data-after="-300"
264
data-dt-element-name="time401"
265
></div>
266
<br/>
@@ -271,7 +271,7 @@ Unfortunatelly, Morris Charts are veeeeeeeeeeeeeeeery slow! We force them to low
271
data-chart-library="morris"
272
data-width="100%"
273
data-height="200"
274
- data-after="-600"
274
+ data-after="-300"
275
data-dt-element-name="time402"
276
></div>
277
<br/>
@@ -282,7 +282,7 @@ Unfortunatelly, Morris Charts are veeeeeeeeeeeeeeeery slow! We force them to low
282
data-chart-library="morris"
283
data-width="100%"
284
data-height="200"
285
- data-after="-600"
285
+ data-after="-300"
286
data-dt-element-name="time403"
287
></div>
288
<br/>
web/dashboard.js
+249
-192
@@ -88,18 +88,30 @@
88
NETDATA.options = {
89
targets: null,
90
updated_dom: 1,
91
- debug: 0,
91
last_paused: 0,
92
+ page_is_visible: 1,
93
94
current: {
95
pixels_per_point: 1,
96
idle_between_charts: 100,
97
idle_between_loops: 500,
98
+ idle_lost_focus: 500,
99
fast_render_timeframe: 200 // render continously for these many ms
100
+ },
101
+
102
+ debug: {
103
+ show_boxes: 0,
104
+ main_loop: 0,
105
+ focus: 1,
106
+ visibility: 0,
107
+ chart_data_url: 1,
108
+ chart_errors: 1,
109
+ chart_timing: 0,
110
+ chart_calls: 0,
111
}
112
}
113
102
- if(NETDATA.options.debug) console.log('welcome to NETDATA');
114
+ if(NETDATA.options.debug.main_loop) console.log('welcome to NETDATA');
115
116
117
// ----------------------------------------------------------------------------------------------------------------
@@ -139,10 +151,10 @@
151
self = $(element);
152
153
bgcolor = ""
142
- if(NETDATA.options.debug)
154
+ if(NETDATA.options.debug.show_boxes)
155
bgcolor = " background-color: lightgrey;";
156
145
- element.innerHTML = '<div style="overflow: hidden;' + bgcolor + ' width: 100%; height: 100%;"><small>'
157
+ element.innerHTML = '<div style="font-size: xx-small; overflow: hidden;' + bgcolor + ' width: 100%; height: 100%;"><small>'
158
+ message
159
+ '</small></div>';
160
@@ -150,9 +162,10 @@
162
}
163
164
// ----------------------------------------------------------------------------------------------------------------
165
+ // Library functions
166
+
167
// Load a script without jquery
168
// This is used to load jquery - after it is loaded, we use jquery
155
-
169
NETDATA._loadjQuery = function(callback) {
170
if(typeof jQuery == 'undefined') {
171
var script = document.createElement('script');
@@ -172,6 +185,62 @@
185
callback();
186
}
187
188
+ NETDATA.ColorLuminance = function(hex, lum) {
189
+ // validate hex string
190
+ hex = String(hex).replace(/[^0-9a-f]/gi, '');
191
+ if (hex.length < 6)
192
+ hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
193
+
194
+ lum = lum || 0;
195
+
196
+ // convert to decimal and change luminosity
197
+ var rgb = "#", c, i;
198
+ for (i = 0; i < 3; i++) {
199
+ c = parseInt(hex.substr(i*2,2), 16);
200
+ c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
201
+ rgb += ("00"+c).substr(c.length);
202
+ }
203
+
204
+ return rgb;
205
+ }
206
+
207
+ NETDATA.guid = function() {
208
+ function s4() {
209
+ return Math.floor((1 + Math.random()) * 0x10000)
210
+ .toString(16)
211
+ .substring(1);
212
+ }
213
+
214
+ return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
215
+ }
216
+
217
+ // this is the main function - where everything starts
218
+ NETDATA.init = function() {
219
+ // this should be called only once
220
+
221
+ $(window).blur(function() {
222
+ NETDATA.options.page_is_visible = 0;
223
+ if(NETDATA.options.debug.focus) console.log('Lost Focus!');
224
+ });
225
+
226
+ $(window).focus(function() {
227
+ NETDATA.options.page_is_visible = 1;
228
+ if(NETDATA.options.debug.focus) console.log('Focus restored!');
229
+ });
230
+
231
+ NETDATA.getDomCharts(function() {
232
+ NETDATA.chartRefresher(0);
233
+ });
234
+ }
235
+
236
+ // user function to signal us the DOM has been
237
+ // updated.
238
+ NETDATA.updatedDom = function() {
239
+ NETDATA.options.updated_dom = 1;
240
+ }
241
+
242
+ // ----------------------------------------------------------------------------------------------------------------
243
+
244
NETDATA.generateChartDataURL = function() {
245
self = $(this);
246
@@ -191,12 +260,14 @@
260
pixels_per_point = NETDATA.options.current.pixels_per_point
261
262
var points = self.data('points') || Math.round(width / pixels_per_point);
263
+ var format = self.data('format') || NETDATA.chartLibraries[library].format;
264
+ var options = self.data('options') || NETDATA.chartLibraries[library].options;
265
266
// build the data URL
267
var url = host + chart.data_url;
197
- url += "&format=" + NETDATA.chartLibraries[library].format;
268
+ url += "&format=" + format;
269
url += "&points=" + points.toString();
199
- url += "&options=" + NETDATA.chartLibraries[library].options;
270
+ url += "&options=" + options;
271
url += "&group=" + method;
272
273
if(after)
@@ -213,16 +284,16 @@
284
.data('calculated-points', points)
285
.data('calculated-url', url);
286
216
- if(NETDATA.options.debug) console.log('generateChartDataURL(): ' + url + ' WxH:' + width + 'x' + height + ' points: ' + points + ' library: ' + library);
287
+ if(NETDATA.options.debug.chart_data_url) console.log('generateChartDataURL(): ' + url + ' WxH:' + width + 'x' + height + ' points: ' + points + ' library: ' + library);
288
return url;
289
}
290
291
NETDATA.validateDomCharts = function(targets, index, callback) {
221
- if(NETDATA.options.debug) console.log('validateDomCharts() working on ' + index);
292
+ if(NETDATA.options.debug.main_loop) console.log('validateDomCharts() working on ' + index);
293
294
var target = targets.get(index);
295
if(target == null) {
225
- if(NETDATA.options.debug) console.log('validateDomCharts(): all ' + (index - 1) + ' charts parsed.');
296
+ if(NETDATA.options.debug.main_loop) console.log('validateDomCharts(): all ' + (index - 1) + ' charts parsed.');
297
if(typeof callback == 'function') callback();
298
}
299
else {
@@ -237,7 +308,7 @@
308
var host = self.data('host') || NETDATA.chartDefaults.host;
309
var library = self.data('chart-library') || NETDATA.chartDefaults.library;
310
240
- if(NETDATA.options.debug) console.log('validateDomCharts() parsing ' + id + ' of type ' + library);
311
+ if(NETDATA.options.debug.main_loop) console.log('validateDomCharts() parsing ' + id + ' of type ' + library);
312
313
if(typeof NETDATA.chartLibraries[library] == 'undefined') {
314
NETDATA.error(402, library);
@@ -287,11 +358,11 @@
358
NETDATA.sizeDomCharts = function(targets, index, callback) {
359
// this is used to quickly size all charts to their size
360
290
- if(NETDATA.options.debug) console.log('sizeDomCharts() working on ' + index);
361
+ if(NETDATA.options.debug.main_loop) console.log('sizeDomCharts() working on ' + index);
362
363
var target = targets.get(index);
364
if(target == null) {
294
- if(NETDATA.options.debug) console.log('sizeDomCharts(): all ' + (index - 1) + ' charts sized.');
365
+ if(NETDATA.options.debug.main_loop) console.log('sizeDomCharts(): all ' + (index - 1) + ' charts sized.');
366
if(typeof callback == 'function') callback();
367
}
368
else {
@@ -317,8 +388,8 @@
388
NETDATA.options.targets = $('div[data-netdata]').filter(':visible')
389
.bind('create', function(event, data) {
390
var self = $(this);
320
-
321
- if(NETDATA.options.debug)
391
+
392
+ if(NETDATA.options.debug.chart_errors)
393
NETDATA.chartLibraries[self.data('chart-library')].create(this, data);
394
else {
395
try {
@@ -332,7 +403,7 @@
403
})
404
.bind('update', function(event, data) {
405
var self = $(this);
335
- if(NETDATA.options.debug)
406
+ if(NETDATA.options.debug.chart_errors)
407
NETDATA.chartLibraries[self.data('chart-library')].update(this, data);
408
else {
409
try {
@@ -345,7 +416,7 @@
416
}
417
});
418
348
- if(NETDATA.options.debug)
419
+ if(NETDATA.options.debug.main_loop)
420
console.log('DOM updated - there are ' + NETDATA.options.targets.length + ' charts on page.');
421
422
NETDATA.sizeDomCharts(NETDATA.options.targets, 0, function() {
@@ -353,13 +424,6 @@
424
});
425
}
426
356
- NETDATA.init = function() {
357
- // this should be called only once
358
- NETDATA.getDomCharts(function() {
359
- NETDATA.chartRefresher(0);
360
- });
361
- }
362
-
427
// ----------------------------------------------------------------------------------------------------------------
428
429
//var chart = function() {
@@ -380,15 +444,15 @@
444
// check if this chart has to be refreshed now
445
var now = new Date().getTime();
446
if(last + every > now) {
383
- console.log(self.data('netdata') + ' too soon - skipping.');
447
+ if(NETDATA.options.debug.chart_timing) console.log(self.data('netdata') + ' too soon - skipping.');
448
if(typeof callback == 'function') callback();
449
}
450
else if(!self.visible(true)) {
387
- console.log(self.data('netdata') + ' is NOT visible.');
451
+ if(NETDATA.options.debug.visibility) console.log(self.data('netdata') + ' is NOT visible.');
452
if(typeof callback == 'function') callback();
453
}
454
else {
391
- console.log(self.data('netdata') + ' is visible, downloading data...');
455
+ if(NETDATA.options.debug.visibility) console.log(self.data('netdata') + ' is visible, downloading data...');
456
$.ajax( {
457
url: NETDATA.generateChartDataURL.call(element), // self.data('chart-url'),
458
crossDomain: true
@@ -396,13 +460,18 @@
460
.then(function(data) {
461
var started = new Date().getTime();
462
463
+ // if the result is JSON, find the latest update-every
464
+ if(NETDATA.chartLibraries[self.data('chart-library')].jsonWrapper &&
465
+ typeof data.update_every != 'undefined')
466
+ self.data('update-every', data.update_every * 1000);
467
+
468
if(self.data('created')) {
400
- console.log('updating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
469
+ if(NETDATA.options.debug.chart_calls) console.log('updating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
470
self.trigger('update', [data]);
471
// NETDATA.chartLibraries[self.data('chart-library')].update(element, data);
472
}
473
else {
405
- console.log('creating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
474
+ if(NETDATA.options.debug.chart_calls) console.log('creating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
475
self.trigger('create', [data]);
476
//NETDATA.chartLibraries[self.data('chart-library')].create(element, data);
477
self.data('created', true);
@@ -432,63 +501,63 @@
501
};
502
503
NETDATA.chartRefresher = function(index) {
435
- // if(NETDATA.options.debug) console.log('NETDATA.chartRefresher(<targets, ' + index + ')');
504
+ // if(NETDATA.options.debug.mail_loop) console.log('NETDATA.chartRefresher(<targets, ' + index + ')');
505
437
- now = new Date().getTime();
438
-
439
- if(NETDATA.options.updated_dom) {
440
- NETDATA.getDomCharts(function() {
441
- NETDATA.chartRefresher(0);
442
- });
506
+ if(!NETDATA.options.page_is_visible) {
507
+ if(NETDATA.options.debug.main_loop) console.log('waiting focus...');
508
+ setTimeout(function() {
509
+ NETDATA.chartRefresher(index);
510
+ }, NETDATA.options.current.idle_lost_focus);
511
}
512
else {
445
- var target = NETDATA.options.targets.get(index);
446
- if(target == null) {
447
- if(NETDATA.options.debug) console.log('waiting to restart main loop...');
448
- NETDATA.options.last_paused = now;
513
+ now = new Date().getTime();
514
450
- setTimeout(function() {
515
+ if(NETDATA.options.updated_dom) {
516
+ // the dom has been updated
517
+ // get the dom parts again
518
+ NETDATA.getDomCharts(function() {
519
NETDATA.chartRefresher(0);
452
- }, NETDATA.options.current.idle_between_loops);
520
+ });
521
}
522
else {
455
- var self = $(target);
456
- if(!self.data('enabled')) {
457
- NETDATA.chartRefresher(++index);
523
+ var target = NETDATA.options.targets.get(index);
524
+ if(target == null) {
525
+ if(NETDATA.options.debug.main_loop) console.log('waiting to restart main loop...');
526
+ NETDATA.options.last_paused = now;
527
+
528
+ setTimeout(function() {
529
+ NETDATA.chartRefresher(0);
530
+ }, NETDATA.options.current.idle_between_loops);
531
}
532
else {
460
- if(now - NETDATA.options.last_paused < NETDATA.options.current.fast_render_timeframe) {
461
- if(NETDATA.options.debug) console.log('fast rendering...');
462
-
463
- NETDATA.chartValuesDownloader(target, function() {
464
- NETDATA.chartRefresher(++index);
465
- });
533
+ var self = $(target);
534
+ if(!self.data('enabled')) {
535
+ NETDATA.chartRefresher(++index);
536
}
537
else {
468
- if(NETDATA.options.debug) console.log('waiting for next refresh...');
469
- NETDATA.options.last_paused = now;
538
+ if(now - NETDATA.options.last_paused < NETDATA.options.current.fast_render_timeframe) {
539
+ if(NETDATA.options.debug.main_loop) console.log('fast rendering...');
540
471
- setTimeout(function() {
541
NETDATA.chartValuesDownloader(target, function() {
542
NETDATA.chartRefresher(++index);
543
});
475
- }, NETDATA.options.current.idle_between_charts);
544
+ }
545
+ else {
546
+ if(NETDATA.options.debug.main_loop) console.log('waiting for next refresh...');
547
+ NETDATA.options.last_paused = now;
548
+
549
+ setTimeout(function() {
550
+ NETDATA.chartValuesDownloader(target, function() {
551
+ NETDATA.chartRefresher(++index);
552
+ });
553
+ }, NETDATA.options.current.idle_between_charts);
554
+ }
555
}
556
}
557
}
558
}
559
}
560
482
- NETDATA.guid = function() {
483
- function s4() {
484
- return Math.floor((1 + Math.random()) * 0x10000)
485
- .toString(16)
486
- .substring(1);
487
- }
488
-
489
- return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
490
- }
491
-
561
// ----------------------------------------------------------------------------------------------------------------
562
// peity
563
@@ -517,7 +586,7 @@
586
var self = $(element);
587
var instance = self.data('peity-instance');
588
var ins = $(instance);
520
- ins.html(data);
589
+ ins.html(data.result);
590
591
// peity.change() does not accept options
592
// to pass width and height
@@ -529,7 +598,7 @@
598
var self = $(element);
599
600
var uuid = NETDATA.guid();
532
- element.innerHTML = '<div id="' + uuid + '">' + data + '</div>';
601
+ element.innerHTML = '<div id="' + uuid + '">' + data.result + '</div>';
602
var instance = document.getElementById(uuid);
603
var ins = $(instance);
604
@@ -569,58 +638,58 @@
638
var options = self.data('sparkline-options');
639
options.width = self.data('calculated-width');
640
options.height = self.data('calculated-height');
572
- self.sparkline(data, options);
641
+ self.sparkline(data.result, options);
642
}
643
644
NETDATA.sparklineChartCreate = function(element, data) {
645
var self = $(element);
646
var chart = self.data('chart');
647
var type = self.data('sparkline-type') || 'line';
579
- var lineColor = self.data('sparkline-lineColor') || undefined;
580
- var fillColor = self.data('sparkline-fillColor') || (chart.chart_type == 'line')?'#FFF':undefined;
581
- var chartRangeMin = self.data('sparkline-chartRangeMin') || undefined;
582
- var chartRangeMax = self.data('sparkline-chartRangeMax') || undefined;
648
+ var lineColor = self.data('sparkline-linecolor') || NETDATA.colors[0];
649
+ var fillColor = self.data('sparkline-fillcolor') || (chart.chart_type == 'line')?'#FFF':NETDATA.ColorLuminance(lineColor, 0.8);
650
+ var chartRangeMin = self.data('sparkline-chartrangemin') || undefined;
651
+ var chartRangeMax = self.data('sparkline-chartrangemax') || undefined;
652
var composite = self.data('sparkline-composite') || undefined;
584
- var enableTagOptions = self.data('sparkline-enableTagOptions') || undefined;
585
- var tagOptionPrefix = self.data('sparkline-tagOptionPrefix') || undefined;
586
- var tagValuesAttribute = self.data('sparkline-tagValuesAttribute') || undefined;
587
- var disableHiddenCheck = self.data('sparkline-disableHiddenCheck') || undefined;
588
- var defaultPixelsPerValue = self.data('sparkline-defaultPixelsPerValue') || undefined;
589
- var spotColor = self.data('sparkline-spotColor') || undefined;
590
- var minSpotColor = self.data('sparkline-minSpotColor') || undefined;
591
- var maxSpotColor = self.data('sparkline-maxSpotColor') || undefined;
592
- var spotRadius = self.data('sparkline-spotRadius') || undefined;
593
- var valueSpots = self.data('sparkline-valueSpots') || undefined;
594
- var highlightSpotColor = self.data('sparkline-highlightSpotColor') || undefined;
595
- var highlightLineColor = self.data('sparkline-highlightLineColor') || undefined;
596
- var lineWidth = self.data('sparkline-lineWidth') || undefined;
597
- var normalRangeMin = self.data('sparkline-normalRangeMin') || undefined;
598
- var normalRangeMax = self.data('sparkline-normalRangeMax') || undefined;
599
- var drawNormalOnTop = self.data('sparkline-drawNormalOnTop') || undefined;
653
+ var enableTagOptions = self.data('sparkline-enabletagoptions') || undefined;
654
+ var tagOptionPrefix = self.data('sparkline-tagoptionprefix') || undefined;
655
+ var tagValuesAttribute = self.data('sparkline-tagvaluesattribute') || undefined;
656
+ var disableHiddenCheck = self.data('sparkline-disablehiddencheck') || undefined;
657
+ var defaultPixelsPerValue = self.data('sparkline-defaultpixelspervalue') || undefined;
658
+ var spotColor = self.data('sparkline-spotcolor') || undefined;
659
+ var minSpotColor = self.data('sparkline-minspotcolor') || undefined;
660
+ var maxSpotColor = self.data('sparkline-maxspotcolor') || undefined;
661
+ var spotRadius = self.data('sparkline-spotradius') || undefined;
662
+ var valueSpots = self.data('sparkline-valuespots') || undefined;
663
+ var highlightSpotColor = self.data('sparkline-highlightspotcolor') || undefined;
664
+ var highlightLineColor = self.data('sparkline-highlightlinecolor') || undefined;
665
+ var lineWidth = self.data('sparkline-linewidth') || undefined;
666
+ var normalRangeMin = self.data('sparkline-normalrangemin') || undefined;
667
+ var normalRangeMax = self.data('sparkline-normalrangemax') || undefined;
668
+ var drawNormalOnTop = self.data('sparkline-drawnormalontop') || undefined;
669
var xvalues = self.data('sparkline-xvalues') || undefined;
601
- var chartRangeClip = self.data('sparkline-chartRangeClip') || undefined;
670
+ var chartRangeClip = self.data('sparkline-chartrangeclip') || undefined;
671
var xvalues = self.data('sparkline-xvalues') || undefined;
603
- var chartRangeMinX = self.data('sparkline-chartRangeMinX') || undefined;
604
- var chartRangeMaxX = self.data('sparkline-chartRangeMaxX') || undefined;
605
- var disableInteraction = self.data('sparkline-disableInteraction') || false;
606
- var disableTooltips = self.data('sparkline-disableTooltips') || false;
607
- var disableHighlight = self.data('sparkline-disableHighlight') || false;
608
- var highlightLighten = self.data('sparkline-highlightLighten') || 1.4;
609
- var highlightColor = self.data('sparkline-highlightColor') || undefined;
610
- var tooltipContainer = self.data('sparkline-tooltipContainer') || undefined;
611
- var tooltipClassname = self.data('sparkline-tooltipClassname') || undefined;
612
- var tooltipFormat = self.data('sparkline-tooltipFormat') || undefined;
613
- var tooltipPrefix = self.data('sparkline-tooltipPrefix') || undefined;
614
- var tooltipSuffix = self.data('sparkline-tooltipSuffix') || ' ' + chart.units;
615
- var tooltipSkipNull = self.data('sparkline-tooltipSkipNull') || true;
616
- var tooltipValueLookups = self.data('sparkline-tooltipValueLookups') || undefined;
617
- var tooltipFormatFieldlist = self.data('sparkline-tooltipFormatFieldlist') || undefined;
618
- var tooltipFormatFieldlistKey = self.data('sparkline-tooltipFormatFieldlistKey') || undefined;
619
- var numberFormatter = self.data('sparkline-numberFormatter') || function(n){ return n.toFixed(2); };
620
- var numberDigitGroupSep = self.data('sparkline-numberDigitGroupSep') || undefined;
621
- var numberDecimalMark = self.data('sparkline-numberDecimalMark') || undefined;
622
- var numberDigitGroupCount = self.data('sparkline-numberDigitGroupCount') || undefined;
623
- var animatedZooms = self.data('sparkline-animatedZooms') || false;
672
+ var chartRangeMinX = self.data('sparkline-chartrangeminx') || undefined;
673
+ var chartRangeMaxX = self.data('sparkline-chartrangemaxx') || undefined;
674
+ var disableInteraction = self.data('sparkline-disableinteraction') || false;
675
+ var disableTooltips = self.data('sparkline-disabletooltips') || false;
676
+ var disableHighlight = self.data('sparkline-disablehighlight') || false;
677
+ var highlightLighten = self.data('sparkline-highlightlighten') || 1.4;
678
+ var highlightColor = self.data('sparkline-highlightcolor') || undefined;
679
+ var tooltipContainer = self.data('sparkline-tooltipcontainer') || undefined;
680
+ var tooltipClassname = self.data('sparkline-tooltipclassname') || undefined;
681
+ var tooltipFormat = self.data('sparkline-tooltipformat') || undefined;
682
+ var tooltipPrefix = self.data('sparkline-tooltipprefix') || undefined;
683
+ var tooltipSuffix = self.data('sparkline-tooltipsuffix') || ' ' + chart.units;
684
+ var tooltipSkipNull = self.data('sparkline-tooltipskipnull') || true;
685
+ var tooltipValueLookups = self.data('sparkline-tooltipvaluelookups') || undefined;
686
+ var tooltipFormatFieldlist = self.data('sparkline-tooltipformatfieldlist') || undefined;
687
+ var tooltipFormatFieldlistKey = self.data('sparkline-tooltipformatfieldlistkey') || undefined;
688
+ var numberFormatter = self.data('sparkline-numberformatter') || function(n){ return n.toFixed(2); };
689
+ var numberDigitGroupSep = self.data('sparkline-numberdigitgroupsep') || undefined;
690
+ var numberDecimalMark = self.data('sparkline-numberdecimalmark') || undefined;
691
+ var numberDigitGroupCount = self.data('sparkline-numberdigitgroupcount') || undefined;
692
+ var animatedZooms = self.data('sparkline-animatedzooms') || false;
693
694
var options = {
695
type: type,
@@ -677,10 +746,10 @@
746
element.innerHTML = '<div style="display: inline-block; position: relative;" id="' + uuid + '"></div>';
747
var div = document.getElementById(uuid);
748
680
- self.sparkline(data, options);
749
+ self.sparkline(data.result, options);
750
self.data('sparkline-options', options)
682
- .data('uuid', uuid)
683
- .data('created', true);
751
+ .data('uuid', uuid)
752
+ .data('created', true);
753
};
754
755
// ----------------------------------------------------------------------------------------------------------------
@@ -732,70 +801,61 @@
801
var self = $(element);
802
var dygraph = self.data('dygraph-instance');
803
735
- if(typeof data.update_every != 'undefined')
736
- self.data('update-every', data.update_every * 1000);
737
-
738
- if(dygraph != null) {
739
- console.log('updating dygraphs');
740
- dygraph.updateOptions({
741
- file: data.data,
742
- labels: data.labels,
743
- labelsDivWidth: self.width() - 70
744
- });
745
- }
746
- else
747
- console.log('not updating dygraphs');
804
+ dygraph.updateOptions({
805
+ file: data.result.data,
806
+ labels: data.result.labels,
807
+ labelsDivWidth: self.width() - 70
808
+ });
809
};
810
811
NETDATA.dygraphChartCreate = function(element, data) {
812
var self = $(element);
813
var chart = self.data('chart');
814
var title = self.data('dygraph-title') || chart.title;
754
- var titleHeight = self.data('dygraph-titleHeight') || 20;
755
- var labelsDiv = self.data('dygraph-labelsDiv') || undefined;
756
- var connectSeparatedPoints = self.data('dygraph-connectSeparatedPoints') || false;
757
- var yLabelWidth = self.data('dygraph-yLabelWidth') || 12;
758
- var stackedGraph = self.data('dygraph-stackedGraph') || (chart.chart_type == 'stacked')?true:false;
759
- var stackedGraphNaNFill = self.data('dygraph-stackedGraphNaNFill') || 'none';
760
- var hideOverlayOnMouseOut = self.data('dygraph-hideOverlayOnMouseOut') || true;
761
- var fillGraph = self.data('dygraph-fillGraph') || (chart.chart_type == 'area')?true:false;
762
- var drawPoints = self.data('dygraph-drawPoints') || false;
763
- var labelsDivStyles = self.data('dygraph-labelsDivStyles') || { 'fontSize':'10px' };
764
- // var labelsDivWidth = self.data('dygraph-labelsDivWidth') || 250;
765
- var labelsDivWidth = self.width() - 70;
766
- var labelsSeparateLines = self.data('dygraph-labelsSeparateLines') || false;
767
- var labelsShowZeroValues = self.data('dygraph-labelsShowZeroValues') || true;
815
+ var titleHeight = self.data('dygraph-titleheight') || 20;
816
+ var labelsDiv = self.data('dygraph-labelsdiv') || undefined;
817
+ var connectSeparatedPoints = self.data('dygraph-connectseparatedpoints') || false;
818
+ var yLabelWidth = self.data('dygraph-ylabelwidth') || 12;
819
+ var stackedGraph = self.data('dygraph-stackedgraph') || (chart.chart_type == 'stacked')?true:false;
820
+ var stackedGraphNaNFill = self.data('dygraph-stackedgraphnanfill') || 'none';
821
+ var hideOverlayOnMouseOut = self.data('dygraph-hideoverlayonmouseout') || true;
822
+ var fillGraph = self.data('dygraph-fillgraph') || (chart.chart_type == 'area')?true:false;
823
+ var drawPoints = self.data('dygraph-drawpoints') || false;
824
+ var labelsDivStyles = self.data('dygraph-labelsdivstyles') || { 'fontSize':'10px' };
825
+ var labelsDivWidth = self.data('dygraph-labelsdivwidth') || self.width() - 70;
826
+ var labelsSeparateLines = self.data('dygraph-labelsseparatelines') || false;
827
+ var labelsShowZeroValues = self.data('dygraph-labelsshowzerovalues') || true;
828
var legend = self.data('dygraph-legend') || 'onmouseover';
769
- var showLabelsOnHighlight = self.data('dygraph-showLabelsOnHighlight') || true;
770
- var gridLineColor = self.data('dygraph-gridLineColor') || '#EEE';
771
- var axisLineColor = self.data('dygraph-axisLineColor') || '#EEE';
772
- var maxNumberWidth = self.data('dygraph-maxNumberWidth') || 8;
773
- var sigFigs = self.data('dygraph-sigFigs') || null;
774
- var digitsAfterDecimal = self.data('dygraph-digitsAfterDecimal') || 2;
775
- var axisLabelFontSize = self.data('dygraph-axisLabelFontSize') || 10;
776
- var axisLineWidth = self.data('dygraph-axisLineWidth') || 0.3;
777
- var drawAxis = self.data('dygraph-drawAxis') || true;
778
- var strokeWidth = self.data('dygraph-strokeWidth') || 1.0;
779
- var drawGapEdgePoints = self.data('dygraph-drawGapEdgePoints') || true;
829
+ var showLabelsOnHighlight = self.data('dygraph-showlabelsonhighlight') || true;
830
+ var gridLineColor = self.data('dygraph-gridlinecolor') || '#EEE';
831
+ var axisLineColor = self.data('dygraph-axislinecolor') || '#EEE';
832
+ var maxNumberWidth = self.data('dygraph-maxnumberwidth') || 8;
833
+ var sigFigs = self.data('dygraph-sigfigs') || null;
834
+ var digitsAfterDecimal = self.data('dygraph-digitsafterdecimal') || 2;
835
+ var axisLabelFontSize = self.data('dygraph-axislabelfontsize') || 10;
836
+ var axisLineWidth = self.data('dygraph-axislinewidth') || 0.3;
837
+ var drawAxis = self.data('dygraph-drawaxis') || true;
838
+ var strokeWidth = self.data('dygraph-strokewidth') || 1.0;
839
+ var drawGapEdgePoints = self.data('dygraph-drawgapedgepoints') || true;
840
var colors = self.data('dygraph-colors') || NETDATA.colors;
781
- var pointSize = self.data('dygraph-pointSize') || 1;
782
- var stepPlot = self.data('dygraph-stepPlot') || false;
783
- var strokeBorderColor = self.data('dygraph-strokeBorderColor') || 'white';
784
- var strokeBorderWidth = self.data('dygraph-strokeBorderWidth') || (chart.chart_type == 'stacked')?1.0:0.0;
785
- var strokePattern = self.data('dygraph-strokePattern') || undefined;
786
- var highlightCircleSize = self.data('dygraph-highlightCircleSize') || 3;
787
- var highlightSeriesOpts = self.data('dygraph-highlightSeriesOpts') || { strokeWidth: 1.5 };
788
- var highlightSeriesBackgroundAlpha = self.data('dygraph-highlightSeriesBackgroundAlpha') || (chart.chart_type == 'stacked')?0.7:0.5;
789
- var pointClickCallback = self.data('dygraph-pointClickCallback') || undefined;
790
- var showRangeSelector = self.data('dygraph-showRangeSelector') || false;
791
- var showRoller = self.data('dygraph-showRoller') || false;
792
- var valueFormatter = self.data('dygraph-valueFormatter') || undefined; //function(x){ return x.toFixed(2); };
793
- var rightGap = self.data('dygraph-rightGap') || 5;
794
- var drawGrid = self.data('dygraph-drawGrid') || true;
795
- var drawXGrid = self.data('dygraph-drawXGrid') || undefined;
796
- var drawYGrid = self.data('dygraph-drawYGrid') || undefined;
797
- var gridLinePattern = self.data('dygraph-gridLinePattern') || null;
798
- var gridLineWidth = self.data('dygraph-gridLineWidth') || 0.3;
841
+ var pointSize = self.data('dygraph-pointsize') || 1;
842
+ var stepPlot = self.data('dygraph-stepplot') || false;
843
+ var strokeBorderColor = self.data('dygraph-strokebordercolor') || 'white';
844
+ var strokeBorderWidth = self.data('dygraph-strokeborderwidth') || (chart.chart_type == 'stacked')?1.0:0.0;
845
+ var strokePattern = self.data('dygraph-strokepattern') || undefined;
846
+ var highlightCircleSize = self.data('dygraph-highlightcirclesize') || 3;
847
+ var highlightSeriesOpts = self.data('dygraph-highlightseriesopts') || { strokeWidth: 1.5 };
848
+ var highlightSeriesBackgroundAlpha = self.data('dygraph-highlightseriesbackgroundalpha') || (chart.chart_type == 'stacked')?0.7:0.5;
849
+ var pointClickCallback = self.data('dygraph-pointclickcallback') || undefined;
850
+ var showRangeSelector = self.data('dygraph-showrangeselector') || false;
851
+ var showRoller = self.data('dygraph-showroller') || false;
852
+ var valueFormatter = self.data('dygraph-valueformatter') || undefined; //function(x){ return x.toFixed(2); };
853
+ var rightGap = self.data('dygraph-rightgap') || 5;
854
+ var drawGrid = self.data('dygraph-drawgrid') || true;
855
+ var drawXGrid = self.data('dygraph-drawxgrid') || undefined;
856
+ var drawYGrid = self.data('dygraph-drawygrid') || undefined;
857
+ var gridLinePattern = self.data('dygraph-gridlinepattern') || null;
858
+ var gridLineWidth = self.data('dygraph-gridlinewidth') || 0.3;
859
860
var options = {
861
title: title,
@@ -846,7 +906,7 @@
906
showRoller: showRoller,
907
valueFormatter: valueFormatter,
908
rightGap: rightGap,
849
- labels: data.labels,
909
+ labels: data.result.labels,
910
axes: {
911
x: {
912
pixelsPerLabel: 50,
@@ -869,7 +929,7 @@
929
self.html('<div id="' + uuid + '" style="width: 100%; height: 100%;"></div>');
930
931
var dchart = new Dygraph(document.getElementById(uuid),
872
- data.data, options);
932
+ data.result.data, options);
933
934
self.data('dygraph-instance', dchart)
935
.data('dygraph-options', options)
@@ -932,12 +992,9 @@
992
var self = $(element);
993
var morris = self.data('morris-instance');
994
935
- if(typeof data.update_every != 'undefined')
936
- self.data('update-every', data.update_every * 1000);
937
-
995
if(morris != null) {
996
console.log('updating morris');
940
- morris.setData(data.data);
997
+ morris.setData(data.result.data);
998
}
999
else
1000
console.log('not updating morris');
@@ -950,15 +1007,12 @@
1007
var uuid = NETDATA.guid();
1008
self.html('<div id="' + uuid + '" style="width: ' + self.data('calculated-width') + 'px; height: ' + self.data('calculated-height') + 'px;"></div>');
1009
953
- // remove the 'time' element from the labels
954
- data.labels.splice(0, 1);
955
-
1010
var options = {
1011
element: uuid,
958
- data: data.data,
1012
+ data: data.result.data,
1013
xkey: 'time',
960
- ykeys: data.labels,
961
- labels: data.labels,
1014
+ ykeys: data.dimension_names,
1015
+ labels: data.dimension_names,
1016
lineWidth: 2,
1017
pointSize: 2,
1018
smooth: true,
@@ -980,7 +1034,7 @@
1034
morris = new Morris.Area(options);
1035
1036
self.data('morris-instance', morris)
983
- .data('created', true);
1037
+ .data('created', true);
1038
};
1039
1040
// ----------------------------------------------------------------------------------------------------------------
@@ -1058,10 +1112,7 @@
1112
var gchart = self.data('google-instance');
1113
var options = self.data('google-options');
1114
1061
- if(typeof data.update_every != 'undefined')
1062
- self.data('update-every', data.update_every * 1000);
1063
-
1064
- var datatable = new google.visualization.DataTable(data);
1115
+ var datatable = new google.visualization.DataTable(data.result);
1116
1117
gchart.draw(datatable, options);
1118
};
@@ -1070,7 +1121,7 @@
1121
var self = $(element);
1122
var chart = self.data('chart');
1123
1073
- var datatable = new google.visualization.DataTable(data);
1124
+ var datatable = new google.visualization.DataTable(data.result);
1125
var gchart;
1126
1127
var options = {
@@ -1177,7 +1228,8 @@
1228
initialized: false,
1229
enabled: true,
1230
format: 'json',
1180
- options: 'ms|flip',
1231
+ options: 'ms|flip|jsonwrap',
1232
+ jsonWrapper: true,
1233
pixels_per_point: 2,
1234
detects_dimensions_on_update: false
1235
},
@@ -1188,7 +1240,8 @@
1240
initialized: false,
1241
enabled: true,
1242
format: 'array',
1191
- options: 'flip|min2max',
1243
+ options: 'flip|min2max|jsonwrap',
1244
+ jsonWrapper: true,
1245
pixels_per_point: 2,
1246
detects_dimensions_on_update: false
1247
},
@@ -1199,7 +1252,8 @@
1252
initialized: false,
1253
enabled: true,
1254
format: 'ssvcomma',
1202
- options: 'null2zero|flip|min2max',
1255
+ options: 'null2zero|flip|min2max|jsonwrap',
1256
+ jsonWrapper: true,
1257
pixels_per_point: 2,
1258
detects_dimensions_on_update: false
1259
},
@@ -1210,7 +1264,8 @@
1264
initialized: false,
1265
enabled: true,
1266
format: 'json',
1213
- options: 'objectrows|ms',
1267
+ options: 'objectrows|ms|jsonwrap',
1268
+ jsonWrapper: true,
1269
pixels_per_point: 10,
1270
detects_dimensions_on_update: false
1271
},
@@ -1221,7 +1276,8 @@
1276
initialized: false,
1277
enabled: true,
1278
format: 'datatable',
1224
- options: '',
1279
+ options: 'jsonwrap',
1280
+ jsonWrapper: true,
1281
pixels_per_point: 2,
1282
detects_dimensions_on_update: true
1283
},
@@ -1233,6 +1289,7 @@
1289
enabled: true,
1290
format: 'json',
1291
options: '',
1292
+ jsonWrapper: false,
1293
pixels_per_point: 1,
1294
detects_dimensions_on_update: false
1295
}