support for google datasources with JSONP and the variance of JSON used by google charts.
Costa Tsaousis (ktsaou) committed
Apr 15, 2014 at 02:42 UTC
2c468d13bb645148b0c666057de44096689d5d7f
1 file changed
+216
-76
netdata.c
+216
-76
@@ -61,8 +61,14 @@
61
62
#define WEB_PATH_FILE "file"
63
#define WEB_PATH_DATA "data"
64
+#define WEB_PATH_DATASOURCE "datasource"
65
#define WEB_PATH_GRAPH "graph"
66
67
+// type of JSON generations
68
+#define DATASOURCE_JSON 0
69
+#define DATASOURCE_GOOGLE_JSON 1
70
+#define DATASOURCE_GOOGLE_JSONP 2
71
+
72
// internal defaults
73
#define UPDATE_EVERY 1
74
#define UPDATE_EVERY_MAX 3600
@@ -825,9 +831,12 @@ void web_buffer_increase(struct web_buffer *b, size_t free_size_required)
831
#define WEB_CLIENT_MODE_NORMAL 0
832
#define WEB_CLIENT_MODE_FILECOPY 1
833
834
+#define URL_MAX 8192
835
+
836
struct web_client {
837
unsigned long long id;
838
char client_ip[101];
839
+ char last_url[URL_MAX+1];
840
841
struct timeval tv_in, tv_ready;
842
@@ -1090,10 +1099,26 @@ void web_line_free(struct web_line *wl)
1099
free(wl);
1100
}
1101
1093
-void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method)
1102
+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)
1103
{
1104
pthread_mutex_lock(&st->mutex);
1105
1106
+ unsigned long last_timestamp = 0;
1107
+
1108
+ char kq[2] = "\"";
1109
+ char sq[2] = "\"";
1110
+ switch(type) {
1111
+ case DATASOURCE_GOOGLE_JSON:
1112
+ case DATASOURCE_GOOGLE_JSONP:
1113
+ kq[0] = '\0';
1114
+ sq[0] = '\'';
1115
+ break;
1116
+
1117
+ case DATASOURCE_JSON:
1118
+ default:
1119
+ break;
1120
+ }
1121
+
1122
// check the options
1123
if(entries_to_show <= 0) entries_to_show = 1;
1124
if(group_count <= 0) group_count = 1;
@@ -1124,7 +1149,7 @@ void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show
1149
if(!dimensions) {
1150
pthread_mutex_unlock(&st->mutex);
1151
wb->bytes = sprintf(wb->buffer, "No dimensions yet.");
1127
- return;
1152
+ return 0;
1153
}
1154
1155
int line_size = 4096 + (dimensions * 200);
@@ -1137,16 +1162,16 @@ void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show
1162
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
1163
group_values[c] = group_counts[c] = 0;
1164
1140
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "{\n \"cols\":\n [\n");
1141
- wb->bytes += sprintf(&wb->buffer[wb->bytes], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"datetime\"},\n");
1142
- wb->bytes += sprintf(&wb->buffer[wb->bytes], " {\"id\":\"\",\"label\":\"\",\"pattern\":\"\",\"type\":\"string\",\"p\":{\"role\":\"annotation\"}},\n");
1143
- wb->bytes += sprintf(&wb->buffer[wb->bytes], " {\"id\":\"\",\"label\":\"\",\"pattern\":\"\",\"type\":\"string\",\"p\":{\"role\":\"annotationText\"}}");
1165
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "{\n %scols%s:\n [\n", kq, kq);
1166
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], " {%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);
1167
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], " {%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);
1168
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], " {%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);
1169
1170
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
1171
if(!rd->hidden)
1147
- wb->bytes += sprintf(&wb->buffer[wb->bytes], ",\n {\"id\":\"\",\"label\":\"%s\",\"pattern\":\"\",\"type\":\"number\"}", rd->name);
1172
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
1173
1149
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ],\n \"rows\":\n [\n");
1174
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ],\n %srows%s:\n [\n", kq, kq);
1175
1176
// to allow grouping on the same values, we need a pad
1177
pad = current_entry % group_count;
@@ -1193,8 +1218,10 @@ void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show
1218
struct tm *tm = localtime(&st->times[t].tv_sec);
1219
if(!tm) { error("localtime() failed."); continue; }
1220
1196
- sprintf(dtm, "\"Date(%d, %d, %d, %d, %d, %d, %d)\"", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(st->times[t].tv_usec / 1000)); // datetime
1197
- wb->bytes += sprintf(&wb->buffer[wb->bytes], "%s {\"c\":[{\"v\":%s}", printed?"]},\n":"", dtm);
1221
+ if(st->times[t].tv_sec > last_timestamp) last_timestamp = st->times[t].tv_sec;
1222
+
1223
+ sprintf(dtm, "Date(%d, %d, %d, %d, %d, %d, %d)", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(st->times[t].tv_usec / 1000)); // datetime
1224
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "%s {%sc%s:[{%sv%s:%s%s%s}", printed?"]},\n":"", kq, kq, kq, kq, sq, dtm, sq);
1225
1226
print_this = 1;
1227
web_line_reset(wl);
@@ -1260,8 +1287,7 @@ void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show
1287
1288
if(print_this) {
1289
if(!rd->hidden)
1263
- web_line_printf(wl, ",{\"v\":%0.1Lf}", group_values[c]);
1264
- //wb->bytes += sprintf(&wb->buffer[wb->bytes], ",{\"v\":%0.1Lf}", group_values[c]);
1290
+ web_line_printf(wl, ",{%sv%s:%0.1Lf}", kq, kq, group_values[c]);
1291
1292
group_values[c] = group_counts[c] = 0;
1293
}
@@ -1270,11 +1296,11 @@ void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show
1296
if(print_this) {
1297
if(annotate_reset) {
1298
annotation_count++;
1273
- wb->bytes += sprintf(&wb->buffer[wb->bytes], ",{\"v\":\"RESET OR OVERFLOW\"},{\"v\":\"The counters have been wrapped.\"}");
1299
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
1300
annotate_reset = 0;
1301
}
1302
else {
1277
- wb->bytes += sprintf(&wb->buffer[wb->bytes], ",{\"v\":null},{\"v\":null}");
1303
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1304
}
1305
1306
strcpy(&wb->buffer[wb->bytes], wl->buffer);
@@ -1289,6 +1315,7 @@ void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show
1315
web_line_free(wl);
1316
1317
pthread_mutex_unlock(&st->mutex);
1318
+ return last_timestamp;
1319
}
1320
1321
int mysendfile(struct web_client *w, char *filename)
@@ -1299,9 +1326,10 @@ int mysendfile(struct web_client *w, char *filename)
1326
while (filename[0] == '/') filename = &filename[1];
1327
1328
// if the filename contain known paths, skip them
1302
- if(strncmp(filename, WEB_PATH_DATA "/", strlen(WEB_PATH_DATA) + 1) == 0) filename = &filename[strlen(WEB_PATH_DATA) + 1];
1303
- else if(strncmp(filename, WEB_PATH_GRAPH "/", strlen(WEB_PATH_GRAPH) + 1) == 0) filename = &filename[strlen(WEB_PATH_GRAPH) + 1];
1304
- else if(strncmp(filename, WEB_PATH_FILE "/", strlen(WEB_PATH_FILE) + 1) == 0) filename = &filename[strlen(WEB_PATH_FILE) + 1];
1329
+ if(strncmp(filename, WEB_PATH_DATA "/", strlen(WEB_PATH_DATA) + 1) == 0) filename = &filename[strlen(WEB_PATH_DATA) + 1];
1330
+ else if(strncmp(filename, WEB_PATH_DATASOURCE "/", strlen(WEB_PATH_DATASOURCE) + 1) == 0) filename = &filename[strlen(WEB_PATH_DATASOURCE) + 1];
1331
+ else if(strncmp(filename, WEB_PATH_GRAPH "/", strlen(WEB_PATH_GRAPH) + 1) == 0) filename = &filename[strlen(WEB_PATH_GRAPH) + 1];
1332
+ else if(strncmp(filename, WEB_PATH_FILE "/", strlen(WEB_PATH_FILE) + 1) == 0) filename = &filename[strlen(WEB_PATH_FILE) + 1];
1333
1334
// if the filename contains a / or a .., refuse to serve it
1335
if(strstr(filename, "/") != 0 || strstr(filename, "..") != 0) {
@@ -1349,7 +1377,7 @@ int mysendfile(struct web_client *w, char *filename)
1377
}
1378
}
1379
1352
- syslog(LOG_NOTICE, "%llu: Sending file '%s' to client %s.", w->id, filename, w->client_ip);
1380
+ //syslog(LOG_NOTICE, "%llu: Sending file '%s' to client %s.", w->id, filename, w->client_ip);
1381
1382
// pick a Content-Type for the file
1383
if(strstr(filename, ".html") != NULL) w->data->contenttype = CT_TEXT_HTML;
@@ -1387,6 +1415,21 @@ char *mystrsep(char **ptr, char *s)
1415
1416
void web_client_reset(struct web_client *w)
1417
{
1418
+ struct timeval tv;
1419
+ gettimeofday(&tv, NULL);
1420
+
1421
+ long sent = w->zoutput?w->zstream.total_out:(w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rbytes:w->data->bytes;
1422
+ long size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rbytes:w->data->bytes;
1423
+ syslog(LOG_NOTICE, "%llu: (sent/all = %ld/%ld bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: '%s'",
1424
+ w->id,
1425
+ sent, size, -((size>0)?((float)(size-sent)/(float)size * 100.0):0.0),
1426
+ (float)usecdiff(&w->tv_ready, &w->tv_in) / 1000.0,
1427
+ (float)usecdiff(&tv, &w->tv_ready) / 1000.0,
1428
+ (float)usecdiff(&tv, &w->tv_in) / 1000.0,
1429
+ (w->mode == WEB_CLIENT_MODE_FILECOPY)?"filecopy":"data",
1430
+ w->last_url
1431
+ );
1432
+
1433
debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
1434
1435
if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
@@ -1468,6 +1511,140 @@ void web_client_enable_deflate(struct web_client *w) {
1511
debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
1512
}
1513
1514
+int web_client_data_request(struct web_client *w, char *url, int datasource_type)
1515
+{
1516
+ char *args = strchr(url, '?');
1517
+ if(args) {
1518
+ *args='\0';
1519
+ args = &args[1];
1520
+ }
1521
+
1522
+ // get the name of the data to show
1523
+ char *tok = mystrsep(&url, "/");
1524
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1525
+
1526
+ // do we have such a data set?
1527
+ RRD_STATS *st = rrd_stats_find_byname(tok);
1528
+ if(!st) st = rrd_stats_find(tok);
1529
+ if(!st) {
1530
+ // we don't have it
1531
+ // try to send a file with that name
1532
+ w->data->bytes = 0;
1533
+ return(mysendfile(w, tok));
1534
+ }
1535
+
1536
+ // we have it
1537
+ debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
1538
+
1539
+ // how many entries does the client want?
1540
+ size_t lines = save_history;
1541
+ size_t group_count = 1;
1542
+ int group_method = GROUP_AVERAGE;
1543
+
1544
+ if(url) {
1545
+ // parse the lines required
1546
+ tok = mystrsep(&url, "/");
1547
+ if(tok) lines = atoi(tok);
1548
+ if(lines < 5) lines = save_history;
1549
+ }
1550
+ if(url) {
1551
+ // parse the group count required
1552
+ tok = mystrsep(&url, "/");
1553
+ if(tok) group_count = atoi(tok);
1554
+ if(group_count < 1) group_count = 1;
1555
+ if(group_count > save_history / 20) group_count = save_history / 20;
1556
+ }
1557
+ if(url) {
1558
+ // parse the grouping method required
1559
+ tok = mystrsep(&url, "/");
1560
+ if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
1561
+ else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1562
+ else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1563
+ }
1564
+
1565
+ w->data->contenttype = CT_APPLICATION_JSON;
1566
+ w->data->bytes = 0;
1567
+
1568
+ char *google_version = "0.6";
1569
+ char *google_reqId = "0";
1570
+ char *google_sig = "0";
1571
+ char *google_out = "json";
1572
+ char *google_responseHandler = "google.visualization.Query.setResponse";
1573
+ char *google_outFileName = NULL;
1574
+ unsigned long last_timestamp_in_data = 0;
1575
+ if(datasource_type == DATASOURCE_GOOGLE_JSON || datasource_type == DATASOURCE_GOOGLE_JSONP) {
1576
+
1577
+ while(args) {
1578
+ tok = mystrsep(&args, "&");
1579
+ if(tok) {
1580
+ char *name = mystrsep(&tok, "=");
1581
+ if(name && strcmp(name, "tqx") == 0) {
1582
+ char *key = mystrsep(&tok, ":");
1583
+ char *value = mystrsep(&tok, ";");
1584
+ if(key && value && *key && *value) {
1585
+ if(strcmp(key, "version") == 0)
1586
+ google_version = value;
1587
+
1588
+ else if(strcmp(key, "reqId") == 0)
1589
+ google_reqId = value;
1590
+
1591
+ else if(strcmp(key, "sig") == 0)
1592
+ google_sig = value;
1593
+
1594
+ else if(strcmp(key, "out") == 0)
1595
+ google_out = value;
1596
+
1597
+ else if(strcmp(key, "responseHandler") == 0)
1598
+ google_responseHandler = value;
1599
+
1600
+ else if(strcmp(key, "outFileName") == 0)
1601
+ google_outFileName = value;
1602
+ }
1603
+ }
1604
+ }
1605
+ }
1606
+
1607
+ debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
1608
+ w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
1609
+ );
1610
+
1611
+ if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
1612
+ last_timestamp_in_data = strtoul(google_sig, NULL, 0);
1613
+
1614
+ // check the client wants json
1615
+ if(strcmp(google_out, "json") != 0) {
1616
+ w->data->bytes = snprintf(w->data->buffer, w->data->size,
1617
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
1618
+ google_responseHandler, google_version, google_reqId, google_out);
1619
+ return 200;
1620
+ }
1621
+ }
1622
+ }
1623
+
1624
+ if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
1625
+ w->data->bytes = snprintf(w->data->buffer, w->data->size,
1626
+ "%s({version:'%s',reqId:'%s',status:'ok',sig:'%lu',table:",
1627
+ google_responseHandler, google_version, google_reqId, st->last_updated);
1628
+ }
1629
+
1630
+ 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);
1631
+ unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->data, lines, group_count, group_method);
1632
+
1633
+ if(datasource_type == DATASOURCE_GOOGLE_JSONP) {
1634
+ if(timestamp_in_data > last_timestamp_in_data)
1635
+ w->data->bytes += snprintf(&w->data->buffer[w->data->bytes], w->data->size - w->data->bytes, "});");
1636
+
1637
+ else {
1638
+ // the client already has the latest data
1639
+ w->data->bytes = snprintf(w->data->buffer, w->data->size,
1640
+ "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
1641
+ google_responseHandler, google_version, google_reqId);
1642
+ }
1643
+ }
1644
+
1645
+ return 200;
1646
+}
1647
+
1648
void web_client_process(struct web_client *w)
1649
{
1650
int code = 500;
@@ -1488,6 +1665,10 @@ void web_client_process(struct web_client *w)
1665
if(strstr(w->data->buffer, "gzip"))
1666
web_client_enable_deflate(w);
1667
1668
+ int datasource_type = DATASOURCE_GOOGLE_JSONP;
1669
+ //if(strstr(w->data->buffer, "X-DataSource-Auth"))
1670
+ // datasource_type = DATASOURCE_GOOGLE_JSON;
1671
+
1672
char *buf = w->data->buffer;
1673
char *tok = strsep(&buf, " \r\n");
1674
char *url = NULL;
@@ -1506,65 +1687,23 @@ void web_client_process(struct web_client *w)
1687
debug(D_WEB_CLIENT, "%llu: I don't know how to handle POST with form data. Assuming it is a GET on url '%s'.", w->id, url);
1688
}
1689
1690
+ w->last_url[0] = '\0';
1691
if(url) {
1692
+ strncpy(w->last_url, url, URL_MAX);
1693
+ w->last_url[URL_MAX] = '\0';
1694
+
1695
tok = mystrsep(&url, "/?&");
1696
1697
debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1698
1699
if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1700
// the client is requesting rrd data
1516
-
1517
- // get the name of the data to show
1518
- tok = mystrsep(&url, "/?&");
1519
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1520
-
1521
- // do we have such a data set?
1522
- RRD_STATS *st = rrd_stats_find_byname(tok);
1523
- if(!st) st = rrd_stats_find(tok);
1524
- if(!st) {
1525
- // we don't have it
1526
- // try to send a file with that name
1527
- w->data->bytes = 0;
1528
- code = mysendfile(w, tok);
1529
- }
1530
- else {
1531
- // we have it
1532
- debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
1533
-
1534
- // how many entries does the client want?
1535
- size_t lines = save_history;
1536
- size_t group_count = 1;
1537
- int group_method = GROUP_AVERAGE;
1538
-
1539
- if(url) {
1540
- // parse the lines required
1541
- tok = mystrsep(&url, "/?&");
1542
- if(tok) lines = atoi(tok);
1543
- if(lines < 5) lines = save_history;
1544
- }
1545
- if(url) {
1546
- // parse the group count required
1547
- tok = mystrsep(&url, "/?&");
1548
- if(tok) group_count = atoi(tok);
1549
- if(group_count < 1) group_count = 1;
1550
- if(group_count > save_history / 20) group_count = save_history / 20;
1551
- }
1552
- if(url) {
1553
- // parse the grouping method required
1554
- tok = mystrsep(&url, "/?&");
1555
- if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
1556
- else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1557
- else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1558
- }
1559
-
1560
- syslog(LOG_NOTICE, "%llu: Sending '%s' data to client %s.", w->id, st->name, w->client_ip);
1561
- 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);
1562
-
1563
- code = 200;
1564
- w->data->contenttype = CT_APPLICATION_JSON;
1565
- w->data->bytes = 0;
1566
- rrd_stats_json(st, w->data, lines, group_count, group_method);
1567
- }
1701
+ datasource_type = DATASOURCE_JSON;
1702
+ code = web_client_data_request(w, url, datasource_type);
1703
+ }
1704
+ else if(strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
1705
+ // the client is requesting google datasource
1706
+ code = web_client_data_request(w, url, datasource_type);
1707
}
1708
else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
1709
// the client is requesting an rrd graph
@@ -1583,7 +1722,6 @@ void web_client_process(struct web_client *w)
1722
}
1723
else {
1724
code = 200;
1586
- syslog(LOG_NOTICE, "%llu: Sending '%s' graph to client %s.", w->id, st->name, w->client_ip);
1725
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1726
w->data->contenttype = CT_APPLICATION_JSON;
1727
w->data->bytes = 0;
@@ -1594,7 +1732,6 @@ void web_client_process(struct web_client *w)
1732
code = 200;
1733
1734
debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
1597
- syslog(LOG_NOTICE, "%llu: mirroring client %s.", w->id, w->client_ip);
1735
1736
// just leave the buffer as is
1737
// it will be copied back to the client
@@ -1602,7 +1739,6 @@ void web_client_process(struct web_client *w)
1739
else if(strcmp(tok, "list") == 0) {
1740
code = 200;
1741
1605
- syslog(LOG_NOTICE, "%llu: Sending text list of all monitors to client %s.", w->id, w->client_ip);
1742
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
1743
1744
w->data->bytes = 0;
@@ -1615,7 +1751,6 @@ void web_client_process(struct web_client *w)
1751
code = 200;
1752
1753
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending envlist of RRD_STATS...", w->id);
1618
- syslog(LOG_NOTICE, "%llu: Sending envlist to client %s.", w->id, w->client_ip);
1754
1755
w->data->bytes = 0;
1756
RRD_STATS *st = root;
@@ -1628,7 +1763,6 @@ void web_client_process(struct web_client *w)
1763
else if(strcmp(tok, "all.json") == 0) {
1764
code = 200;
1765
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
1631
- syslog(LOG_NOTICE, "%llu: Sending list with all graphs in JSON to client %s.", w->id, w->client_ip);
1766
1767
w->data->contenttype = CT_APPLICATION_JSON;
1768
w->data->bytes = 0;
@@ -1655,6 +1789,8 @@ void web_client_process(struct web_client *w)
1789
1790
}
1791
else {
1792
+ strcpy(w->last_url, "not a valid response");
1793
+
1794
if(buf) debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, buf);
1795
1796
code = 500;
@@ -1667,6 +1803,8 @@ void web_client_process(struct web_client *w)
1803
if(pointer_to_free) free(pointer_to_free);
1804
}
1805
else if(w->data->bytes > 8192) {
1806
+ strcpy(w->last_url, "too big request");
1807
+
1808
debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big.", w->id);
1809
1810
code = 400;
@@ -1685,7 +1823,6 @@ void web_client_process(struct web_client *w)
1823
}
1824
1825
gettimeofday(&w->tv_ready, NULL);
1688
- debug(D_WEB_CLIENT, "%llu: Generated response of %ld bytes in %llu microseconds.", w->id, w->data->bytes, usecdiff(&w->tv_ready, &w->tv_in));
1826
w->data->date = time(NULL);
1827
w->data->sent = 0;
1828
@@ -2272,6 +2409,8 @@ void *socket_listen_main(void *ptr)
2409
2410
if(pthread_detach(w->thread) != 0)
2411
error("%llu: Cannot request detach of newly created thread.", w->id);
2412
+
2413
+ syslog(LOG_NOTICE, "%llu: %s connected", w->id, w->client_ip);
2414
}
2415
else debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything.");
2416
}
@@ -2280,6 +2419,7 @@ void *socket_listen_main(void *ptr)
2419
// cleanup unused clients
2420
for(w = web_clients; w ; w = w?w->next:NULL) {
2421
if(w->obsolete) {
2422
+ syslog(LOG_NOTICE, "%llu: %s disconnected", w->id, w->client_ip);
2423
debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
2424
w = web_client_free(w);
2425
syslog_allocations();