diff --git a/lib/core-net/server.c b/lib/core-net/server.c index 3f692a9bb..19364841f 100644 --- a/lib/core-net/server.c +++ b/lib/core-net/server.c @@ -164,9 +164,9 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len, char *orig = buf, *end = buf + len - 1, first = 1; const struct lws_vhost *vh = context->vhost_list; const struct lws_context_per_thread *pt; - time_t t = time(NULL); - int n, listening = 0, cgi_count = 0; + int n, listening = 0, cgi_count = 0, fd; struct lws_conn_stats cs; + time_t t = time(NULL); double d = 0; #ifdef LWS_WITH_CGI struct lws_cgi * const *pcgi; @@ -196,6 +196,22 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len, } #endif + fd = lws_open("/proc/self/statm", LWS_O_RDONLY); + if (fd >= 0) { + char contents[96], pure[96]; + n = read(fd, contents, sizeof(contents) - 1); + if (n > 0) { + contents[n] = '\0'; + if (contents[n - 1] == '\n') + contents[--n] = '\0'; + lws_json_purify(pure, contents, sizeof(pure)); + + buf += lws_snprintf(buf, end - buf, + "\"statm\": \"%s\",\n", pure); + } + close(fd); + } + buf += lws_snprintf(buf, end - buf, "\"contexts\":[\n"); buf += lws_snprintf(buf, end - buf, "{ " diff --git a/plugins/protocol_lws_server_status.c b/plugins/protocol_lws_server_status.c index 3ffdfde92..9e87ef14b 100644 --- a/plugins/protocol_lws_server_status.c +++ b/plugins/protocol_lws_server_status.c @@ -1,7 +1,7 @@ /* * libwebsockets-test-server - libwebsockets test implementation * - * Copyright (C) 2010-2016 Andy Green + * Copyright (C) 2010 - 2019 Andy Green * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. @@ -37,16 +37,19 @@ struct lws_ss_dumps { int length; }; -struct per_session_data__server_status { +struct pss { int ver; int pos; }; -struct per_vhost_data__lws_server_status { +struct vhd { struct lws_context *context; + struct lws_vhost *vhost; + const struct lws_protocols *protocol; int hide_vhosts; int tow_flag; - int period_us; + int period_s; + int clients; struct lws_ss_dumps d; struct lws_ss_filepath *fp; }; @@ -54,33 +57,23 @@ struct per_vhost_data__lws_server_status { static const struct lws_protocols protocols[1]; static void -update(struct per_vhost_data__lws_server_status *v) +update(struct vhd *v) { struct lws_ss_filepath *fp; - char *p = v->d.buf + LWS_PRE, contents[256], pure[256]; - int n, l, first = 1, fd; + char contents[256], pure[256], *p = v->d.buf + LWS_PRE, + *end = v->d.buf + sizeof(v->d.buf) - LWS_PRE - 1; + int n, first = 1, fd; - l = sizeof(v->d.buf) - LWS_PRE - 1; - - n = lws_snprintf(p, l, "{\"i\":"); - p += n; - l -= n; - - n = lws_json_dump_context(v->context, p, l, v->hide_vhosts); - p += n; - l -= n; - - n = lws_snprintf(p, l, ", \"files\": ["); - p += n; - l -= n; + p += lws_snprintf(p, lws_ptr_diff(end, p), "{\"i\":"); + p += lws_json_dump_context(v->context, p, lws_ptr_diff(end, p), + v->hide_vhosts); + p += lws_snprintf(p, lws_ptr_diff(end, p), ", \"files\": ["); fp = v->fp; while (fp) { - if (!first) { - n = lws_snprintf(p, l, ","); - p += n; - l -= n; - } + if (!first) + p += lws_snprintf(p, lws_ptr_diff(end, p), ","); + fd = lws_open(fp->filepath, LWS_O_RDONLY); if (fd >= 0) { n = read(fd, contents, sizeof(contents) - 1); @@ -88,20 +81,17 @@ update(struct per_vhost_data__lws_server_status *v) contents[n] = '\0'; lws_json_purify(pure, contents, sizeof(pure)); - n = lws_snprintf(p, l, + p += lws_snprintf(p, lws_ptr_diff(end, p), "{\"path\":\"%s\",\"val\":\"%s\"}", fp->filepath, pure); - p += n; - l -= n; first = 0; } close(fd); } + fp = fp->next; } - n = lws_snprintf(p, l, "]}"); - p += n; - + p += lws_snprintf(p, lws_ptr_diff(end, p), "]}"); v->d.length = p - (v->d.buf + LWS_PRE); lws_callback_on_writable_all_protocol(v->context, &protocols[0]); @@ -113,8 +103,7 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, { const struct lws_protocol_vhost_options *pvo = (const struct lws_protocol_vhost_options *)in; - struct per_vhost_data__lws_server_status *v = - (struct per_vhost_data__lws_server_status *) + struct vhd *v = (struct vhd *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); struct lws_ss_filepath *fp, *fp1, **fp_old; @@ -124,8 +113,26 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_ESTABLISHED: lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__); - lws_set_timer_usecs(wsi, v->period_us); - lws_callback_on_writable(wsi); + if (!v->clients++) { + lws_timed_callback_vh_protocol(v->vhost, v->protocol, + LWS_CALLBACK_USER, v->period_s); + lwsl_info("%s: starting updates\n", __func__); + } + update(v); + + break; + + case LWS_CALLBACK_CLOSED: + if (!--v->clients) + lwsl_notice("%s: stopping updates\n", __func__); + + break; + + case LWS_CALLBACK_USER: + update(v); + if (v->clients) + lws_timed_callback_vh_protocol(v->vhost, v->protocol, + LWS_CALLBACK_USER, v->period_s); break; case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ @@ -133,11 +140,10 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, break; lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), - lws_get_protocol(wsi), - sizeof(struct per_vhost_data__lws_server_status)); - v = (struct per_vhost_data__lws_server_status *) - lws_protocol_vh_priv_get(lws_get_vhost(wsi), - lws_get_protocol(wsi)); + lws_get_protocol(wsi), + sizeof(struct vhd)); + v = (struct vhd *)lws_protocol_vh_priv_get(lws_get_vhost(wsi), + lws_get_protocol(wsi)); fp_old = &v->fp; @@ -145,9 +151,9 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, if (!strcmp(pvo->name, "hide-vhosts")) v->hide_vhosts = atoi(pvo->value); if (!strcmp(pvo->name, "update-ms")) - v->period_us = atoi(pvo->value) * 1000; + v->period_s = (atoi(pvo->value) + 500) / 1000; else - v->period_us = 5 * 1000 * 1000; + v->period_s = 5; if (!strcmp(pvo->name, "filepath")) { fp = malloc(sizeof(*fp)); fp->next = NULL; @@ -160,7 +166,11 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, pvo = pvo->next; } v->context = lws_get_context(wsi); + v->vhost = lws_get_vhost(wsi); + v->protocol = lws_get_protocol(wsi); + /* get the initial data */ + update(v); break; case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */ @@ -181,12 +191,6 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, return -1; break; - case LWS_CALLBACK_TIMER: - lws_set_timer_usecs(wsi, v->period_us); - update(v); - lws_callback_on_writable(wsi); - break; - default: break; } @@ -198,7 +202,7 @@ static const struct lws_protocols protocols[] = { { "lws-server-status", callback_lws_server_status, - sizeof(struct per_session_data__server_status), + sizeof(struct pss), 1024, }, }; diff --git a/plugins/server-status.css b/plugins/server-status.css index 6cd32e77b..e6948b7c4 100644 --- a/plugins/server-status.css +++ b/plugins/server-status.css @@ -27,6 +27,13 @@ span.n { text-align:center; color:#808020; } +span.sn { + font-size:12pt; + font-family: Arial; + font-weight:bold; + text-align:center; + color:#808020; +} span.v { font-size:12pt; font-family: Arial; @@ -187,4 +194,4 @@ span.f12 { font-size:12pt } background:#e0e0c0; padding:3px; -webkit-border-radius:3px; - border-radius:3px; } \ No newline at end of file + border-radius:3px; } diff --git a/plugins/server-status.js b/plugins/server-status.js index 24a7826fd..1f20cef18 100644 --- a/plugins/server-status.js +++ b/plugins/server-status.js @@ -17,14 +17,14 @@ function humanize(s) { var i = parseInt(s, 10); - if (i > 1000000000) - return (i / 1000000000).toFixed(3) + "G"; + if (i >= (1024 * 1024 * 1024)) + return (i / (1024 * 1024 * 1024)).toFixed(3) + "Gi"; - if (i > 1000000) - return (i / 1000000).toFixed(3) + "M"; + if (i >= (1024 * 1024)) + return (i / (1024 * 1024)).toFixed(3) + "Mi"; - if (i > 1000) - return (i / 1000).toFixed(3) + "K"; + if (i > 1024) + return (i / 1024).toFixed(3) + "Ki"; return s; } @@ -85,20 +85,26 @@ function ws_open_server_status() s = "
"; s += "Server" + - "Version: " + + "Server Version: " + san(jso.i.version) + "
" + - "Uptime: " + + "Host Uptime: " + ((u / (24 * 3600)) | 0) + "d " + (((u % (24 * 3600)) / 3600) | 0) + "h " + (((u % 3600) / 60) | 0) + "m"; if (jso.i.l1) - s = s + ", Load: " + san(jso.i.l1) + " "; + s = s + ", Host Load: " + san(jso.i.l1) + " "; if (jso.i.l2) s = s + san(jso.i.l2) + " "; if (jso.i.l3) s = s + san(jso.i.l3); if (jso.i.l1) - s =s + ""; + s =s + ""; + + if (jso.i.statm) { + var sm = jso.i.statm.split(" "); + s += ", Virt stack + heap Usage: " + + humanize(parseInt(sm[0], 10) * 4096) + "B"; + } for (n = 0; n < jso.files.length; n++) { s += "
" + san(jso.files[n].path) + ":
" + san(jso.files[n].val); @@ -115,7 +121,7 @@ function ws_open_server_status() "Deprecated Context " + ci + "
"; u = parseInt(san(jso.i.contexts[ci].context_uptime), 10); - s += "Uptime: " + + s += "Server Uptime: " + ((u / (24 * 3600)) | 0) + "d " + (((u % (24 * 3600)) / 3600) | 0) + "h " + (((u % 3600) / 60) | 0) + "m"; @@ -125,8 +131,8 @@ function ws_open_server_status() "Listening wsi: " + san(jso.i.contexts[ci].listen_wsi) + ", " + "Current wsi alive: " + (parseInt(san(jso.i.contexts[ci].wsi_alive), 10) - parseInt(san(jso.i.contexts[ci].listen_wsi), 10)) + "
" + - "Total Rx: " + humanize(san(jso.i.contexts[ci].rx)) +", " + - "Total Tx: " + humanize(san(jso.i.contexts[ci].tx)) +"
" + + "Total Rx: " + humanize(san(jso.i.contexts[ci].rx)) +"B, " + + "Total Tx: " + humanize(san(jso.i.contexts[ci].tx)) +"B
" + "CONNECTIONS: HTTP/1.x: " + san(jso.i.contexts[ci].h1_conn) +", " + "Websocket: " + san(jso.i.contexts[ci].ws_upg) +", " + @@ -174,8 +180,8 @@ function ws_open_server_status() s = s + " (STS)"; s = s +"
" + - "Total Rx: " + humanize(san(jso.i.contexts[ci].vhosts[n].rx)) +", " + - "Total Tx: " + humanize(san(jso.i.contexts[ci].vhosts[n].tx)) +"
" + + "Total Rx: " + humanize(san(jso.i.contexts[ci].vhosts[n].rx)) +"B, " + + "Total Tx: " + humanize(san(jso.i.contexts[ci].vhosts[n].tx)) +"B
" + "CONNECTIONS: HTTP/1.x: " + san(jso.i.contexts[ci].vhosts[n].h1_conn) +", " + "Websocket: " + san(jso.i.contexts[ci].vhosts[n].ws_upg) +", " + @@ -185,29 +191,31 @@ function ws_open_server_status() "TRANSACTIONS: HTTP/1.x: " + san(jso.i.contexts[ci].vhosts[n].h1_trans) + ", " + "H2: " + san(jso.i.contexts[ci].vhosts[n].h2_trans) +", " + - "Total H2 substreams: " + san(jso.i.contexts[ci].vhosts[n].h2_subs) +"
" + + "Total H2 substreams: " + san(jso.i.contexts[ci].vhosts[n].h2_subs) +"
"; - ""; - - var m; - for (m = 0; m < jso.i.contexts[ci].vhosts[n].mounts.length; m++) { - s = s + ""; + if (jso.i.contexts[ci].vhosts[n].mounts) { + s = s + "
MountpointOriginCache Policy
"; - s = s + "" + san(jso.i.contexts[ci].vhosts[n].mounts[m].mountpoint) + - "" + - san(jso.i.contexts[ci].vhosts[n].mounts[m].origin) + - ""; - if (parseInt(san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_max_age), 10)) - s = s + "max-age: " + - san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_max_age) + - ", reuse: " + - san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_reuse) + - ", reval: " + - san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_revalidate) + - ", inter: " + - san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_intermediaries); - s = s + "
"; + + var m; + for (m = 0; m < jso.i.contexts[ci].vhosts[n].mounts.length; m++) { + s = s + ""; + } + s = s + "
MountpointOriginCache Policy
"; + s = s + "" + san(jso.i.contexts[ci].vhosts[n].mounts[m].mountpoint) + + "" + + san(jso.i.contexts[ci].vhosts[n].mounts[m].origin) + + ""; + if (parseInt(san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_max_age), 10)) + s = s + "max-age: " + + san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_max_age) + + ", reuse: " + + san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_reuse) + + ", reval: " + + san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_revalidate) + + ", inter: " + + san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_intermediaries); + s = s + "
"; } - s = s + "
"; s = s + ""; }