@cryptotaxi247 / netdata-1 / commits / 2c468d13b

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();