2
0
Fork 0

[mod_status] Add status.show_runtime action

personal/stbuehler/wip
Thomas Porzelt 2009-08-09 18:04:53 +02:00
parent 8a0665aa53
commit f0d5c9e789
1 changed files with 264 additions and 9 deletions

View File

@ -11,16 +11,21 @@
* status.css <name|url> - set the stylesheet to use
* type: string; values: "default", "blue" or a url to an external css file
* Actions:
* status.page - returns the status page to the client
* status.show - returns the status page to the client
* status.show_runtime - returns the runtime info page to the client
*
* Example config:
* req.path == "/status" {
* req.path == "/srv-status" {
* status.css = "http://mydomain/status.css";
* status.page;
* if req.query == "runtime" {
* status.show_runtime;
* } else {
* status.show;
* }
* }
*
* Todo:
* - handle race condition when connection is gone while collecting data (needs per connection plugin data)
* - add querystring parameters like refresh=X and format=plain
*
* Author:
* Copyright (c) 2008 Thomas Porzelt
@ -112,6 +117,56 @@ static const gchar html_connections_row[] =
" <td>%s</td>\n"
" </tr>\n";
static const gchar html_server_info[] =
" <table cellspacing=\"0\">\n"
" <tr>\n"
" <td class=\"left\" style=\"width: 100px;\">Hostname</td>\n"
" <td class=\"left\">%s</td>\n"
" </tr>\n"
" <tr>\n"
" <td class=\"left\">User</td>\n"
" <td class=\"left\">%s (%u)</td>\n"
" </tr>\n"
" <td class=\"left\">Event handler</td>\n"
" <td class=\"left\">%s</td>\n"
" </table>\n";
static const gchar html_libinfo_th[] =
" <table cellspacing=\"0\">\n"
" <tr>\n"
" <th style=\"width: 100px;\"></th>\n"
" <th style=\"width: 100px;\">linked</th>\n"
" <th style=\"width: 100px;\">headers</th>\n"
" </tr>\n";
static const gchar html_libinfo_row[] =
" <tr>\n"
" <td class=\"left\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" </tr>\n";
static const gchar html_libev_th[] =
" <table cellspacing=\"0\">\n"
" <tr>\n"
" <th style=\"width: 100px;\"></th>\n"
" <th style=\"width: 100px;\">select</th>\n"
" <th style=\"width: 100px;\">poll</th>\n"
" <th style=\"width: 100px;\">epoll</th>\n"
" <th style=\"width: 100px;\">kqueue</th>\n"
" <th style=\"width: 100px;\">/dev/poll</th>\n"
" <th style=\"width: 125px;\">solaris event port</th>\n"
" </tr>\n";
static const gchar html_libev_row[] =
" <tr>\n"
" <td class=\"left\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" <td style=\"text-align: center;\">%s</td>\n"
" </tr>\n";
static const gchar css_default[] =
" <style type=\"text/css\">\n"
" body { margin: 0; padding: 0; font-family: \"lucida grande\",tahoma,verdana,arial,sans-serif; font-size: 12px; }\n"
@ -554,7 +609,7 @@ static void status_collect_cb(gpointer cbdata, gpointer fdata, GPtrArray *result
}
}
static liHandlerResult status_page_handle(liVRequest *vr, gpointer param, gpointer *context) {
static liHandlerResult status_show(liVRequest *vr, gpointer param, gpointer *context) {
if (li_vrequest_handle_direct(vr)) {
liCollectInfo *ci;
mod_status_job *j = g_slice_new(mod_status_job);
@ -571,7 +626,7 @@ static liHandlerResult status_page_handle(liVRequest *vr, gpointer param, gpoint
return (*context) ? LI_HANDLER_WAIT_FOR_EVENT : LI_HANDLER_GO_ON;
}
static liHandlerResult status_page_cleanup(liVRequest *vr, gpointer param, gpointer context) {
static liHandlerResult status_show_cleanup(liVRequest *vr, gpointer param, gpointer context) {
liCollectInfo *ci = (liCollectInfo*) context;
UNUSED(vr);
@ -582,11 +637,210 @@ static liHandlerResult status_page_cleanup(liVRequest *vr, gpointer param, gpoin
return LI_HANDLER_GO_ON;
}
static liAction* status_page(liServer *srv, liPlugin* p, liValue *val) {
static liAction* status_show_create(liServer *srv, liPlugin* p, liValue *val) {
UNUSED(srv);
UNUSED(val);
return li_action_new_function(status_page_handle, status_page_cleanup, NULL, p);
return li_action_new_function(status_show, status_show_cleanup, NULL, p);
}
static gint str_comp(gconstpointer a, gconstpointer b) {
return strcmp(*(const gchar**)a, *(const gchar**)b);
}
static liHandlerResult status_show_runtime(liVRequest *vr, gpointer param, gpointer *context) {
GString *html;
liPlugin* p = param;
GString* css = _OPTION(vr, p, 0).string;
UNUSED(context);
if (!li_vrequest_handle_direct(vr))
return LI_HANDLER_ERROR;
html = g_string_sized_new(2047);
g_string_append_len(html, CONST_STR_LEN(header));
if (!css || !css->len) /* default css */
g_string_append_len(html, CONST_STR_LEN(css_default));
else if (g_str_equal(css->str, "blue")) /* blue css */
g_string_append_len(html, CONST_STR_LEN(css_blue));
else /* external css */
g_string_append_printf(html, " <link rel=\"stylesheet\" rev=\"stylesheet\" href=\"%s\" media=\"screen\" />\n", css->str);
g_string_append_len(html, CONST_STR_LEN(
" </head>\n"
" <body>\n"
));
li_counter_format((guint64)(CUR_TS(vr->wrk) - vr->wrk->srv->started), COUNTER_TIME, vr->wrk->tmp_str);
g_string_append_printf(html, html_top,
vr->request.uri.host->str,
vr->wrk->tmp_str->str,
vr->wrk->srv->started_str->str
);
/* general info */
{
g_string_append_len(html, CONST_STR_LEN(" <div class=\"title\"><strong>Server info</strong></div>\n"));
g_string_append_printf(html, html_server_info,
g_get_host_name(), g_get_user_name(), getuid(), li_ev_backend_string(ev_backend(vr->wrk->loop))
);
}
/* library info */
{
GString *tmp_str = g_string_sized_new(31);
g_string_append_len(html, CONST_STR_LEN(" <div class=\"title\"><strong>Libraries</strong></div>\n"));
g_string_append_len(html, CONST_STR_LEN(html_libinfo_th));
g_string_truncate(tmp_str, 0);
g_string_append_printf(tmp_str, "%u.%u.%u", glib_major_version, glib_minor_version, glib_micro_version);
g_string_truncate(vr->wrk->tmp_str, 0);
g_string_append_printf(vr->wrk->tmp_str, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
g_string_append_printf(html, html_libinfo_row, "GLib",
tmp_str->str,
vr->wrk->tmp_str->str
);
g_string_truncate(tmp_str, 0);
g_string_append_printf(tmp_str, "%u.%u", ev_version_major(), ev_version_minor());
g_string_truncate(vr->wrk->tmp_str, 0);
g_string_append_printf(vr->wrk->tmp_str, "%u.%u", EV_VERSION_MAJOR, EV_VERSION_MINOR);
g_string_append_printf(html, html_libinfo_row, "libev",
tmp_str->str,
vr->wrk->tmp_str->str
);
g_string_append_len(html, CONST_STR_LEN(" </table>\n"));
g_string_free(tmp_str, TRUE);
}
/* libev info */
{
guint i;
g_string_append_len(html, CONST_STR_LEN(" <div class=\"title\"><strong>libev backends</strong></div>\n"));
g_string_append_len(html, CONST_STR_LEN(html_libev_th));
/* supported backend, aka compiled in */
i = ev_supported_backends();
g_string_append_printf(html, html_libev_row, "supported",
i & EVBACKEND_SELECT ? "yes" : "no",
i & EVBACKEND_POLL ? "yes" : "no",
i & EVBACKEND_EPOLL ? "yes" : "no",
i & EVBACKEND_KQUEUE ? "yes" : "no",
i & EVBACKEND_DEVPOLL ? "yes" : "no",
i & EVBACKEND_PORT ? "yes" : "no"
);
/* recommended backends */
i = ev_recommended_backends();
g_string_append_printf(html, html_libev_row, "recommended",
i & EVBACKEND_SELECT ? "yes" : "no",
i & EVBACKEND_POLL ? "yes" : "no",
i & EVBACKEND_EPOLL ? "yes" : "no",
i & EVBACKEND_KQUEUE ? "yes" : "no",
i & EVBACKEND_DEVPOLL ? "yes" : "no",
i & EVBACKEND_PORT ? "yes" : "no"
);
g_string_append_len(html, CONST_STR_LEN(" </table>\n"));
}
/* list modules */
{
guint i, col;
gpointer k, v;
GHashTableIter iter;
GArray *list = g_array_sized_new(FALSE, FALSE, sizeof(gchar*), g_hash_table_size(vr->wrk->srv->plugins));
g_string_append_len(html, CONST_STR_LEN(" <div class=\"title\"><strong>Loaded modules</strong></div>\n"));
g_string_append_len(html, CONST_STR_LEN(" <table cellspacing=\"0\">\n"));
g_hash_table_iter_init(&iter, vr->wrk->srv->plugins);
while (g_hash_table_iter_next(&iter, &k, &v))
g_array_append_val(list, k);
g_array_sort(list, str_comp);
col = 0;
for (i = 1; i < list->len; i++) {
if (col == 0) {
g_string_append_len(html, CONST_STR_LEN(" <tr>\n"));
col++;
}
else if (col == 5) {
g_string_append_len(html, CONST_STR_LEN(" </tr>\n"));
col = 0;
continue;
} else {
col++;
}
g_string_append_printf(html, " <td class=\"left\">%s</td>\n", g_array_index(list, gchar*, i));
}
if (col) {
for (i = 5 - col; i; i--)
g_string_append_len(html, CONST_STR_LEN(" <td></td>\n"));
g_string_append_len(html, CONST_STR_LEN(" </tr>\n"));
}
g_string_append_len(html, CONST_STR_LEN(" </table>\n"));
g_array_free(list, TRUE);
}
/* list environment vars */
{
gchar **e;
gchar **env = g_listenv();
g_string_append_len(html, CONST_STR_LEN(" <div class=\"title\"><strong>Process environment</strong></div>\n"));
g_string_append_len(html, CONST_STR_LEN(" <table cellspacing=\"0\">\n"));
for (e = env; *e; e++) {
g_string_append_printf(html, " <tr><td class=\"left\">%s</td><td class=\"left\">%s</td></tr>\n", *e, getenv(*e));
}
g_string_append_len(html, CONST_STR_LEN(" </table>\n"));
g_strfreev(env);
}
g_string_append_len(html, CONST_STR_LEN(
" </body>\n"
"</html>\n"
));
li_chunkqueue_append_string(vr->out, html);
li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
vr->response.http_status = 200;
return LI_HANDLER_GO_ON;
}
static liAction* status_show_runtime_create(liServer *srv, liPlugin* p, liValue *val) {
UNUSED(srv);
if (val) {
ERROR(srv, "%s", "status.show_runtime expects no parameter");
return NULL;
}
return li_action_new_function(status_show_runtime, NULL, NULL, p);
}
@ -598,7 +852,8 @@ static const liPluginOption options[] = {
};
static const liPluginAction actions[] = {
{ "status.page", status_page },
{ "status.show", status_show_create },
{ "status.show_runtime", status_show_runtime_create },
{ NULL, NULL }
};