@cryptotaxi247 / netdata-1 / commits / 1a7b1af24

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 }