On 6/11/05, Jeff Trawick <[EMAIL PROTECTED]> wrote:
> On 6/11/05, William A. Rowe, Jr. <[EMAIL PROTECTED]> wrote:
> > At 12:34 PM 6/11/2005, Jeff Trawick wrote:
> > >> I like the idea of toggling columns, I'd make it more like
> > >> columns=pid,tid,ss,m,req to allow for abbreviated displays.
> > >
> > >columns= with column names like that works for me
> > >
> > >columns=all displays everything (may change layout in the future)
> > >default list for columns is whatever we display now
> >
> > I like columns=* personally :) Less ambiguous if we decree all columns
> > can be toggled (especially if we allow modules to extend them).
> >
> > Perhaps +/- syntax? Painful in code, but easier for the user
> > (?columns=+tid). +/- wouldn't reorder the columns from their
> > default, while explicit lists would?
No reordering of columns is possible with this patch.
The Srv column is always implicitly enabled.
'*' = all columns (need to escape it on shell command-line)
Bogus values for columns parameter are not reported.
No changes implemented for the no-table flavor of output (yet).
Something that is a bit painful is that APR doesn't have a way to
format a thread id in hex, and that is a useful format for correlation
with some third party logs. That should be resolved eventually so
that the thread id in hex (and perhaps the process id in hex too) can
be requested.
Step in the right direction?
Not usable since somebody is going to implement configurable field order soon?
Broken?
etc.
Thanks for any comments!
Index: modules/generators/mod_status.c
===================================================================
--- modules/generators/mod_status.c (revision 190183)
+++ modules/generators/mod_status.c (working copy)
@@ -71,6 +71,7 @@
#endif
#define APR_WANT_STRFUNC
#include "apr_want.h"
+#include "apr_strings.h"
#ifdef NEXT
#if (NX_CURRENT_COMPILER_RELEASE == 410)
@@ -190,6 +191,7 @@
#define STAT_OPT_REFRESH 0
#define STAT_OPT_NOTABLE 1
#define STAT_OPT_AUTO 2
+#define STAT_OPT_COLUMNS 4
struct stat_opt {
int id;
@@ -202,9 +204,103 @@
{STAT_OPT_REFRESH, "refresh", "Refresh"},
{STAT_OPT_NOTABLE, "notable", NULL},
{STAT_OPT_AUTO, "auto", NULL},
+ {STAT_OPT_COLUMNS, "columns", NULL},
{STAT_OPT_END, NULL, NULL}
};
+#define COL_END -1
+#define COL_PID 1
+#define COL_TID 2
+#define COL_ACC 4
+#define COL_M 8
+#define COL_CPU 16
+#define COL_SS 32
+#define COL_REQ 64
+#define COL_CONN 128
+#define COL_CHILD 256
+#define COL_SLOT 512
+#define COL_CLIENT 1024
+#define COL_VHOST 2048
+#define COL_REQUEST 4096
+#define COL_ALL 0x1FFF
+
+#ifdef HAVE_TIMES
+#define COL_DEFAULT (COL_PID|COL_ACC|COL_M|COL_CPU|COL_SS|COL_REQ|COL_CONN| \
+ COL_CHILD|COL_SLOT|COL_VHOST|COL_REQUEST)
+#else
+#define COL_DEFAULT (COL_PID|COL_ACC|COL_M|COL_SS|COL_REQ|COL_CONN| \
+ COL_CHILD|COL_SLOT|COL_VHOST|COL_REQUEST)
+#endif
+
+struct col_opt {
+ int id;
+ const char *label;
+ const char *heading;
+};
+
+static const struct col_opt column_options[] =
+{
+ {COL_PID, "pid", "PID"},
+ {COL_TID, "tid", "TID"},
+ {COL_ACC, "acc", "Acc"},
+ {COL_M, "m", "M"},
+ {COL_CPU, "cpu", "CPU"},
+ {COL_SS, "ss", "SS"},
+ {COL_REQ, "req", "Req"},
+ {COL_CONN, "conn", "Conn"},
+ {COL_CHILD, "child", "Child"},
+ {COL_SLOT, "slot", "Slot"},
+ {COL_CLIENT, "client", "Client"},
+ {COL_VHOST, "vhost", "VHost"},
+ {COL_REQUEST, "request", "Request"},
+ {COL_ALL, "*", NULL},
+ {COL_END, NULL, NULL}
+};
+
+static int get_columns(apr_pool_t *p, const char *c_arg)
+{
+ char *arg;
+ char *tok, *state;
+ int columns = 0;
+
+ if (ap_strchr_c(c_arg, '+') ||
+ ap_strchr_c(c_arg, '-')) {
+ columns = COL_DEFAULT;
+ }
+
+ arg = apr_pstrdup(p, c_arg);
+ tok = apr_strtok(arg, ",=", &state);
+ while (tok) {
+ int i = 0, plus = 0, minus = 0;
+ if (*tok == '+') {
+ plus = 1;
+ ++tok;
+ }
+ else if (*tok == '-') {
+ minus = 1;
+ ++tok;
+ }
+ else {
+ plus = 1;
+ }
+ while (column_options[i].id != COL_END) {
+ if (!strcasecmp(tok, column_options[i].label)) {
+ if (plus) {
+ columns |= column_options[i].id;
+ }
+ else {
+ columns &= ~column_options[i].id;
+ }
+ break;
+ }
+ ++i;
+ }
+ tok = apr_strtok(NULL, ",=", &state);
+ }
+
+ return columns;
+}
+
static char status_flags[SERVER_NUM_STATUS];
static int status_handler(request_rec *r)
@@ -232,6 +328,7 @@
pid_t *pid_buffer, worker_pid;
clock_t tu, ts, tcu, tcs;
ap_generation_t worker_generation;
+ int columns = COL_DEFAULT;
if (strcmp(r->handler, STATUS_MAGIC_TYPE) &&
strcmp(r->handler, "server-status")) {
@@ -302,6 +399,10 @@
ap_set_content_type(r, "text/plain");
short_report = 1;
break;
+ case STAT_OPT_COLUMNS:
+ columns = get_columns(r->pool,
+ loc +
strlen(status_options[i].form_data_str));
+ break;
}
}
@@ -546,17 +647,17 @@
if (ap_extended_status && !short_report) {
if (no_table_report)
ap_rputs("<hr /><h2>Server Details</h2>\n\n", r);
- else
+ else {
ap_rputs("\n\n<table border=\"0\"><tr>"
- "<th>Srv</th><th>PID</th><th>Acc</th>"
- "<th>M</th>"
-#ifdef HAVE_TIMES
- "<th>CPU\n</th>"
-#endif
- "<th>SS</th><th>Req</th>"
- "<th>Conn</th><th>Child</th><th>Slot</th>"
- "<th>Client</th><th>VHost</th>"
- "<th>Request</th></tr>\n\n", r);
+ "<th>Srv</th>", r);
+ i = 0;
+ while (column_options[i].id != COL_END) {
+ if (column_options[i].heading && columns &
column_options[i].id) {
+ ap_rprintf(r, "<th>%s</th>", column_options[i].heading);
+ }
+ ++i;
+ }
+ }
for (i = 0; i < server_limit; ++i) {
for (j = 0; j < thread_limit; ++j) {
@@ -678,92 +779,156 @@
ws_record->vhost));
}
else { /* !no_table_report */
- if (ws_record->status == SERVER_DEAD)
+ char pid_str[20], tid_str[20];
+
+ pid_str[0] = '\0';
+ tid_str[0] = '\0';
+ if (ws_record->status == SERVER_DEAD) {
+ if (columns & COL_PID) {
+ apr_cpystrn(pid_str, "<td>-</td>", sizeof pid_str);
+ }
+ if (columns & COL_TID) {
+ apr_cpystrn(tid_str, "<td>-</td>", sizeof tid_str);
+ }
+ }
+ else {
+ if (columns & COL_PID) {
+ apr_snprintf(pid_str, sizeof pid_str,
+ "<td>%" APR_PID_T_FMT "</td>",
+ worker_pid);
+ }
+ if (columns & COL_TID) {
+#if APR_HAS_THREADS
+ apr_snprintf(tid_str, sizeof tid_str,
+ "<td>%pT</td>", &ws_record->tid);
+#else
+ apr_snprintf(tid_str, sizeof tid_str,
+ "<td>-</td>");
+#endif
+ }
+ }
+
+ ap_rprintf(r,
+ "<tr><td><b>%d-%d</b></td>%s%s",
+ i, (int)worker_generation,
+ pid_str,
+ tid_str);
+ if (columns & COL_ACC) {
ap_rprintf(r,
-
"<tr><td><b>%d-%d</b></td><td>-</td><td>%d/%lu/%lu",
- i, (int)worker_generation,
+ "<td>%d/%lu/%lu</td>",
(int)conn_lres, my_lres, lres);
- else
+ }
+ if (columns & COL_M) {
+ switch (ws_record->status) {
+ case SERVER_READY:
+ ap_rputs("<td>_\n</td>", r);
+ break;
+ case SERVER_STARTING:
+ ap_rputs("<td><b>S</b>\n</td>", r);
+ break;
+ case SERVER_BUSY_READ:
+ ap_rputs("<td><b>R</b>\n</td>", r);
+ break;
+ case SERVER_BUSY_WRITE:
+ ap_rputs("<td><b>W</b>\n</td>", r);
+ break;
+ case SERVER_BUSY_KEEPALIVE:
+ ap_rputs("<td><b>K</b>\n</td>", r);
+ break;
+ case SERVER_BUSY_LOG:
+ ap_rputs("<td><b>L</b>\n</td>", r);
+ break;
+ case SERVER_BUSY_DNS:
+ ap_rputs("<td><b>D</b>\n</td>", r);
+ break;
+ case SERVER_CLOSING:
+ ap_rputs("<td><b>C</b>\n</td>", r);
+ break;
+ case SERVER_DEAD:
+ ap_rputs("<td>.\n</td>", r);
+ break;
+ case SERVER_GRACEFUL:
+ ap_rputs("<td>G\n</td>", r);
+ break;
+ case SERVER_IDLE_KILL:
+ ap_rputs("<td>I\n</td>", r);
+ break;
+ default:
+ ap_rputs("<td>?\n</td>", r);
+ break;
+ }
+ }
+
+ if (columns & COL_CPU) {
+#ifdef HAVE_TIMES
ap_rprintf(r,
- "<tr><td><b>%d-%d</b></td><td>%"
- APR_PID_T_FMT
- "</td><td>%d/%lu/%lu",
- i, (int)worker_generation,
- worker_pid,
- (int)conn_lres,
- my_lres, lres);
+ "<td>%.2f</td>",
+ (ws_record->times.tms_utime +
+ ws_record->times.tms_stime +
+ ws_record->times.tms_cutime +
+ ws_record->times.tms_cstime) / tick);
+#else
+ ap_rputs("<td>-</td>", r);
+#endif
+ }
+
+ if (columns & COL_SS) {
+ ap_rprintf(r,
+ "<td>%ld</td>",
+ (long)apr_time_sec(nowtime -
+ ws_record->last_used));
+ }
+ if (columns & COL_REQ) {
+ ap_rprintf(r,
+ "<td>%ld</td>",
+ (long)req_time);
+ }
+
+ if (columns & COL_CONN) {
+ ap_rprintf(r, "<td>%-1.1f</td>",
+ (float)conn_bytes / KBYTE);
+ }
- switch (ws_record->status) {
- case SERVER_READY:
- ap_rputs("</td><td>_", r);
- break;
- case SERVER_STARTING:
- ap_rputs("</td><td><b>S</b>", r);
- break;
- case SERVER_BUSY_READ:
- ap_rputs("</td><td><b>R</b>", r);
- break;
- case SERVER_BUSY_WRITE:
- ap_rputs("</td><td><b>W</b>", r);
- break;
- case SERVER_BUSY_KEEPALIVE:
- ap_rputs("</td><td><b>K</b>", r);
- break;
- case SERVER_BUSY_LOG:
- ap_rputs("</td><td><b>L</b>", r);
- break;
- case SERVER_BUSY_DNS:
- ap_rputs("</td><td><b>D</b>", r);
- break;
- case SERVER_CLOSING:
- ap_rputs("</td><td><b>C</b>", r);
- break;
- case SERVER_DEAD:
- ap_rputs("</td><td>.", r);
- break;
- case SERVER_GRACEFUL:
- ap_rputs("</td><td>G", r);
- break;
- case SERVER_IDLE_KILL:
- ap_rputs("</td><td>I", r);
- break;
- default:
- ap_rputs("</td><td>?", r);
- break;
+ if (columns & COL_CHILD) {
+ ap_rprintf(r, "<td>%-2.2f</td>",
+ (float) my_bytes / MBYTE);
}
- ap_rprintf(r,
- "\n</td>"
-#ifdef HAVE_TIMES
- "<td>%.2f</td>"
-#endif
- "<td>%ld</td><td>%ld",
-#ifdef HAVE_TIMES
- (ws_record->times.tms_utime +
- ws_record->times.tms_stime +
- ws_record->times.tms_cutime +
- ws_record->times.tms_cstime) / tick,
-#endif
- (long)apr_time_sec(nowtime -
- ws_record->last_used),
- (long)req_time);
+ if (columns & COL_SLOT) {
+ ap_rprintf(r, "<td>%-2.2f</td>\n",
+ (float)bytes / MBYTE);
+ }
- ap_rprintf(r,
"</td><td>%-1.1f</td><td>%-2.2f</td><td>%-2.2f\n",
- (float)conn_bytes / KBYTE, (float) my_bytes /
MBYTE,
- (float)bytes / MBYTE);
-
- if (ws_record->status == SERVER_BUSY_READ)
- ap_rprintf(r,
- "</td><td>?</td><td nowrap>?</td><td
nowrap>..reading.. </td></tr>\n\n");
- else
- ap_rprintf(r,
- "</td><td>%s</td><td nowrap>%s</td><td
nowrap>%s</td></tr>\n\n",
- ap_escape_html(r->pool,
- ws_record->client),
- ap_escape_html(r->pool,
- ws_record->vhost),
- ap_escape_html(r->pool,
- ws_record->request));
+ if (ws_record->status == SERVER_BUSY_READ) {
+ if (columns & COL_CLIENT) {
+ ap_rputs("<td>?</td>", r);
+ }
+ if (columns & COL_VHOST) {
+ ap_rputs("<td nowrap>?</td>", r);
+ }
+ if (columns & COL_REQUEST) {
+ ap_rputs("<td nowrap>..reading.. </td>", r);
+ }
+ }
+ else {
+ if (columns & COL_CLIENT) {
+ ap_rprintf(r, "<td>%s</td>",
+ ap_escape_html(r->pool,
+ ws_record->client));
+ }
+ if (columns & COL_VHOST) {
+ ap_rprintf(r, "<td nowrap>%s</td>",
+ ap_escape_html(r->pool,
+ ws_record->vhost));
+ }
+ if (columns & COL_REQUEST) {
+ ap_rprintf(r,
+ "<td nowrap>%s</td>",
+ ap_escape_html(r->pool,
+ ws_record->request));
+ }
+ }
+ ap_rputs("</tr>\n\n", r);
} /* no_table_report */
} /* for (j...) */
} /* for (i...) */
@@ -774,6 +939,7 @@
<table>\n \
<tr><th>Srv</th><td>Child Server number - generation</td></tr>\n \
<tr><th>PID</th><td>OS process ID</td></tr>\n \
+<tr><th>TID</th><td>OS thread ID</td></tr>\n \
<tr><th>Acc</th><td>Number of accesses this connection / this child / this
slot</td></tr>\n \
<tr><th>M</th><td>Mode of operation</td></tr>\n"
@@ -786,7 +952,12 @@
<tr><th>Conn</th><td>Kilobytes transferred this connection</td></tr>\n \
<tr><th>Child</th><td>Megabytes transferred this child</td></tr>\n \
<tr><th>Slot</th><td>Total megabytes transferred this slot</td></tr>\n \
+<tr><th>Client</th><td>Client host</td></tr>\n \
+<tr><th>VHost</th><td>VirtualHost selected for this request</td></tr>\n \
+<tr><th>Request</th><td>The request</td><?tr>\n \
</table>\n", r);
+ ap_rputs("<p>Use column headings to select columns "
+ "(e.g., ?columns=pid,m,vhost,request)</p>\r", r);
}
} /* if (ap_extended_status && !short_report) */
else {