static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; buffer *b = buffer_init(); double avg; time_t ts; char buf[32]; unsigned int k; unsigned int l; /* output total number of requests */ buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: ")); avg = p->abs_requests; snprintf(buf, sizeof(buf) - 1, "%.0f", avg); buffer_append_string(b, buf); buffer_append_string_len(b, CONST_STR_LEN("\n")); /* output total traffic out in kbytes */ buffer_append_string_len(b, CONST_STR_LEN("Total kBytes: ")); avg = p->abs_traffic_out / 1024; snprintf(buf, sizeof(buf) - 1, "%.0f", avg); buffer_append_string(b, buf); buffer_append_string_len(b, CONST_STR_LEN("\n")); /* output uptime */ buffer_append_string_len(b, CONST_STR_LEN("Uptime: ")); ts = srv->cur_ts - srv->startup_ts; buffer_append_int(b, ts); buffer_append_string_len(b, CONST_STR_LEN("\n")); /* output busy servers */ buffer_append_string_len(b, CONST_STR_LEN("BusyServers: ")); buffer_append_int(b, srv->conns->used); buffer_append_string_len(b, CONST_STR_LEN("\n")); buffer_append_string_len(b, CONST_STR_LEN("IdleServers: ")); buffer_append_int(b, srv->conns->size - srv->conns->used); buffer_append_string_len(b, CONST_STR_LEN("\n")); /* output scoreboard */ buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: ")); for (k = 0; k < srv->conns->used; k++) { connection *c = srv->conns->ptr[k]; const char *state = connection_get_short_state(c->state); buffer_append_string_len(b, state, 1); } for (l = 0; l < srv->conns->size - srv->conns->used; l++) { buffer_append_string_len(b, CONST_STR_LEN("_")); } buffer_append_string_len(b, CONST_STR_LEN("\n")); chunkqueue_append_buffer(con->write_queue, b); buffer_free(b); /* set text/plain output */ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain")); return 0; }
static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; buffer *b; size_t j; double avg; char multiplier = '\0'; char buf[32]; time_t ts; int days, hours, mins, seconds; b = chunkqueue_get_append_buffer(con->write_queue); BUFFER_COPY_STRING_CONST(b, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" " <head>\n" " <title>Status</title>\n"); BUFFER_APPEND_STRING_CONST(b, " <style type=\"text/css\">\n" " table.status { border: black solid thin; }\n" " td.int { background-color: #f0f0f0; text-align: right }\n" " td.string { background-color: #f0f0f0; text-align: left }\n" " th.status { background-color: black; color: white; font-weight: bold; }\n" " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n" " span.sortarrow { color: white; text-decoration: none; }\n" " </style>\n"); if (p->conf.sort) { BUFFER_APPEND_STRING_CONST(b, "<script type=\"text/javascript\">\n" "// <!--\n" "var sort_column;\n" "var prev_span = null;\n"); BUFFER_APPEND_STRING_CONST(b, "function get_inner_text(el) {\n" " if((typeof el == 'string')||(typeof el == 'undefined'))\n" " return el;\n" " if(el.innerText)\n" " return el.innerText;\n" " else {\n" " var str = \"\";\n" " var cs = el.childNodes;\n" " var l = cs.length;\n" " for (i=0;i<l;i++) {\n" " if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n" " else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n" " }\n" " }\n" " return str;\n" "}\n"); BUFFER_APPEND_STRING_CONST(b, "function sortfn(a,b) {\n" " var at = get_inner_text(a.cells[sort_column]);\n" " var bt = get_inner_text(b.cells[sort_column]);\n" " if (a.cells[sort_column].className == 'int') {\n" " return parseInt(at)-parseInt(bt);\n" " } else {\n" " aa = at.toLowerCase();\n" " bb = bt.toLowerCase();\n" " if (aa==bb) return 0;\n" " else if (aa<bb) return -1;\n" " else return 1;\n" " }\n" "}\n"); BUFFER_APPEND_STRING_CONST(b, "function resort(lnk) {\n" " var span = lnk.childNodes[1];\n" " var table = lnk.parentNode.parentNode.parentNode.parentNode;\n" " var rows = new Array();\n" " for (j=1;j<table.rows.length;j++)\n" " rows[j-1] = table.rows[j];\n" " sort_column = lnk.parentNode.cellIndex;\n" " rows.sort(sortfn);\n"); BUFFER_APPEND_STRING_CONST(b, " if (prev_span != null) prev_span.innerHTML = '';\n" " if (span.getAttribute('sortdir')=='down') {\n" " span.innerHTML = '↑';\n" " span.setAttribute('sortdir','up');\n" " rows.reverse();\n" " } else {\n" " span.innerHTML = '↓';\n" " span.setAttribute('sortdir','down');\n" " }\n" " for (i=0;i<rows.length;i++)\n" " table.tBodies[0].appendChild(rows[i]);\n" " prev_span = span;\n" "}\n" "// -->\n" "</script>\n"); } BUFFER_APPEND_STRING_CONST(b, " </head>\n" " <body>\n"); /* connection listing */ BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>"); BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">"); buffer_append_string_buffer(b, con->uri.authority); BUFFER_APPEND_STRING_CONST(b, " ("); buffer_append_string_buffer(b, con->server_name); BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">"); ts = srv->cur_ts - srv->startup_ts; days = ts / (60 * 60 * 24); ts %= (60 * 60 * 24); hours = ts / (60 * 60); ts %= (60 * 60); mins = ts / (60); ts %= (60); seconds = ts; if (days) { buffer_append_long(b, days); BUFFER_APPEND_STRING_CONST(b, " days "); } if (hours) { buffer_append_long(b, hours); BUFFER_APPEND_STRING_CONST(b, " hours "); } if (mins) { buffer_append_long(b, mins); BUFFER_APPEND_STRING_CONST(b, " min "); } buffer_append_long(b, seconds); BUFFER_APPEND_STRING_CONST(b, " s"); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">"); ts = srv->startup_ts; strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts)); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests; mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out; mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests / (srv->cur_ts - srv->startup_ts); mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts); mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"); for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_requests[j]; } avg /= 5; BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_traffic_out[j]; } avg /= 5; BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "</table>\n"); BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n"); BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n"); BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n"); BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n"); BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n"); BUFFER_APPEND_STRING_CONST(b, "<b>"); buffer_append_long(b, srv->conns->used); BUFFER_APPEND_STRING_CONST(b, " connections</b>\n"); for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; const char *state = connection_get_short_state(c->state); buffer_append_string_len(b, state, 1); if (((j + 1) % 50) == 0) { BUFFER_APPEND_STRING_CONST(b, "\n"); } } BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n"); BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">\n"); BUFFER_APPEND_STRING_CONST(b, "<tr>"); mod_status_header_append_sort(b, p_d, "Client IP"); mod_status_header_append_sort(b, p_d, "Read"); mod_status_header_append_sort(b, p_d, "Written"); mod_status_header_append_sort(b, p_d, "State"); mod_status_header_append_sort(b, p_d, "Time"); mod_status_header_append_sort(b, p_d, "Host"); mod_status_header_append_sort(b, p_d, "URI"); mod_status_header_append_sort(b, p_d, "File"); BUFFER_APPEND_STRING_CONST(b, "</tr>\n"); for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">"); buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr))); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); if (con->request.content_length) { buffer_append_long(b, c->request_content_queue->bytes_in); BUFFER_APPEND_STRING_CONST(b, "/"); buffer_append_long(b, c->request.content_length); } else { BUFFER_APPEND_STRING_CONST(b, "0/0"); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); buffer_append_off_t(b, chunkqueue_written(c->write_queue)); BUFFER_APPEND_STRING_CONST(b, "/"); buffer_append_off_t(b, chunkqueue_length(c->write_queue)); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); buffer_append_string(b, connection_get_state(c->state)); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); buffer_append_long(b, srv->cur_ts - c->request_start); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); if (buffer_is_empty(c->server_name)) { buffer_append_string_buffer(b, c->uri.authority); } else { buffer_append_string_buffer(b, c->server_name); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); if (!buffer_is_empty(c->uri.path)) { buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); buffer_append_string_buffer(b, c->physical.path); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); } BUFFER_APPEND_STRING_CONST(b, "</table>\n"); BUFFER_APPEND_STRING_CONST(b, " </body>\n" "</html>\n" ); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); return 0; }