support range of data
Costa Tsaousis (ktsaou) committed
Apr 21, 2014 at 23:06 UTC
0146dd93820f45e24b602a86eaf8db0cab56bbcb
1 file changed
+67
-22
netdata.c
+67
-22
@@ -943,10 +943,29 @@ struct web_client *web_client_free(struct web_client *w)
943
#define GROUP_AVERAGE 0
944
#define GROUP_MAX 1
945
946
+// find the oldest entry in the data, skipping all empty slots
947
+size_t rrd_stats_first_entry(RRD_STATS *st)
948
+{
949
+ size_t first_entry = st->current_entry + 1;
950
+ if(first_entry >= st->entries) first_entry = 0;
951
+
952
+ while(st->times[first_entry].tv_sec == 0 && first_entry != st->current_entry) {
953
+ first_entry++;
954
+ if(first_entry >= st->entries) first_entry = 0;
955
+ }
956
+
957
+ return first_entry;
958
+}
959
+
960
void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
961
{
962
web_buffer_increase(wb, 16384);
963
964
+ pthread_mutex_lock(&st->mutex);
965
+
966
+ size_t first_entry = rrd_stats_first_entry(st);
967
+ time_t first_entry_t = st->times[first_entry].tv_sec;
968
+
969
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t{\n");
970
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"id\" : \"%s\",\n", st->id);
971
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"name\" : \"%s\",\n", st->name);
@@ -966,12 +985,16 @@ void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
985
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"units\" : \"%s\",\n", st->units);
986
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
987
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"entries\" : %ld,\n", st->entries);
969
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"current\" : %ld,\n", st->current_entry);
988
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"first_entry\" : %ld,\n", first_entry);
989
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"first_entry_t\" : %ld,\n", first_entry_t);
990
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry\" : %ld,\n", st->current_entry);
991
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry_t\" : %lu,\n", st->last_updated);
992
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_entry_secs_ago\" : %lu,\n", time(NULL) - st->last_updated);
993
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"update_every\" : %d,\n", update_every);
971
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated\" : %lu,\n", st->last_updated);
972
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated_secs_ago\" : %lu,\n", time(NULL) - st->last_updated);
994
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"isdetail\" : %d\n", st->isdetail);
995
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t}");
996
+
997
+ pthread_mutex_unlock(&st->mutex);
998
}
999
1000
#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
@@ -1047,7 +1070,7 @@ long double rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
1070
return(0);
1071
}
1072
1050
-unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method)
1073
+unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method, time_t after, time_t before)
1074
{
1075
pthread_mutex_lock(&st->mutex);
1076
@@ -1070,14 +1093,12 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1093
// check the options
1094
if(entries_to_show <= 0) entries_to_show = 1;
1095
if(group_count <= 0) group_count = 1;
1073
- if(group_count > st->entries / 20) group_count = st->entries / 20;
1096
+ // if(group_count > st->entries / 20) group_count = st->entries / 20;
1097
1098
size_t printed = 0; // the lines of JSON data we have generated so far
1099
1100
size_t current_entry = st->current_entry;
1101
size_t t, lt; // t = the current entry, lt = the lest entry of data
1079
- long count = st->entries; // count down of the entries examined so far
1080
- long pad = 0; // align the entries when grouping values together
1102
1103
RRD_DIMENSION *rd;
1104
size_t c = 0; // counter for dimension loops
@@ -1128,20 +1149,19 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1149
1150
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ],\n %srows%s:\n [\n", kq, kq);
1151
1131
- // to allow grouping on the same values, we need a pad
1132
- pad = current_entry % group_count;
1133
-
1152
// make sure current_entry is within limits
1153
if(current_entry < 0 || current_entry >= st->entries) current_entry = 0;
1154
+ if(before == 0) before = st->times[current_entry].tv_sec;
1155
1137
- // find the old entry of the round-robin
1138
- t = current_entry + 1;
1139
- if(t >= st->entries) t = 0;
1156
+ // find the oldest entry of the round-robin
1157
+ t = rrd_stats_first_entry(st);
1158
lt = t;
1159
+ size_t stop_entry = t;
1160
1142
- // find the current entry
1161
+ // skip the oldest, to have incremental data
1162
t++;
1163
if(t >= st->entries) t = 0;
1164
+ if(after == 0) after = st->times[t].tv_sec;
1165
1166
// the minimum line length we expect
1167
int line_size = 4096 + (dimensions * 200);
@@ -1154,23 +1174,30 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1174
int normal_annotation_len = snprintf(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1175
normal_annotation[200] = '\0';
1176
1177
+ // count down of the entries examined so far
1178
+ long count = ((before - after) / update_every) + 1;
1179
+
1180
+ // to allow grouping on the same values, we need a pad
1181
+ long pad = before % group_count;
1182
+
1183
+ // debug(D_RRD_STATS, "after = %lu, before = %lu, diff = %lu, pad = %ld, count = %ld, entries_to_show = %lu, group_count = %lu, current_entry = %lu, t = %lu", after, before, before - after, pad, count, entries_to_show, group_count, current_entry, t);
1184
+
1185
// the loop in dimension data
1158
- count -= 2;
1186
int annotate_reset = 0;
1160
- for ( ; t != current_entry && count >= 0 ; lt = t++, count--) {
1187
+ for ( ; t != stop_entry && count >= 0 ; lt = t++) {
1188
int print_this = 0;
1189
1190
if(t >= st->entries) t = 0;
1191
1165
- // if the last is empty, loop again
1166
- if(!st->times[lt].tv_sec) continue;
1192
+ // make sure we return data in the proper time range
1193
+ if(st->times[t].tv_sec < after || st->times[t].tv_sec > before) continue;
1194
+ count--;
1195
1196
// check if we may exceed the buffer provided
1197
web_buffer_increase(wb, line_size);
1198
1199
// prefer the most recent last entries
1172
- if(((count-pad) / group_count) > entries_to_show) continue;
1173
-
1200
+ if(((count-pad) / group_count) >= entries_to_show) continue;
1201
1202
// ok. we will use this entry!
1203
// find how much usec since the previous entry
@@ -1178,7 +1205,10 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1205
usec = usecdiff(&st->times[t], &st->times[lt]);
1206
1207
if(((count-pad) % group_count) == 0) {
1181
- if(printed >= entries_to_show) break;
1208
+ if(printed >= entries_to_show) {
1209
+ // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
1210
+ break;
1211
+ }
1212
1213
// generate the local date time
1214
struct tm *tm = localtime(&st->times[t].tv_sec);
@@ -1280,6 +1310,8 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1310
if(printed) wb->bytes += sprintf(&wb->buffer[wb->bytes], "]}");
1311
wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ]\n}\n");
1312
1313
+ // debug(D_RRD_STATS, "last_timestamp = %lu", last_timestamp);
1314
+
1315
pthread_mutex_unlock(&st->mutex);
1316
return last_timestamp;
1317
}
@@ -1508,6 +1540,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
1540
// how many entries does the client want?
1541
size_t lines = save_history;
1542
size_t group_count = 1;
1543
+ time_t after = 0, before = 0;
1544
int group_method = GROUP_AVERAGE;
1545
1546
if(url) {
@@ -1530,6 +1563,18 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
1563
else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1564
else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1565
}
1566
+ if(url) {
1567
+ // parse after time
1568
+ tok = mystrsep(&url, "/");
1569
+ if(tok) after = strtoul(tok, NULL, 10);
1570
+ if(after < 0) after = 0;
1571
+ }
1572
+ if(url) {
1573
+ // parse before time
1574
+ tok = mystrsep(&url, "/");
1575
+ if(tok) before = strtoul(tok, NULL, 10);
1576
+ if(before < 0) before = 0;
1577
+ }
1578
1579
w->data->contenttype = CT_APPLICATION_JSON;
1580
w->data->bytes = 0;
@@ -1599,7 +1644,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
1644
}
1645
1646
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group_count, %d group_method).", w->id, st->name, st->id, lines, group_count, group_method);
1602
- unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method);
1647
+ unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method, after, before);
1648
1649
if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
1650
if(timestamp_in_data > last_timestamp_in_data)