Guest User

Untitled

a guest
Jun 1st, 2011
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 31.87 KB | None | 0 0
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2.  * contributor license agreements.  See the NOTICE file distributed with
  3.  * this work for additional information regarding copyright ownership.
  4.  * The ASF licenses this file to You under the Apache License, Version 2.0
  5.  * (the "License"); you may not use this file except in compliance with
  6.  * the License.  You may obtain a copy of the License at
  7.  *
  8.  *     http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16.  
  17. /* Status Module.  Display lots of internal data about how Apache is
  18.  * performing and the state of all children processes.
  19.  *
  20.  * To enable this, add the following lines into any config file:
  21.  *
  22.  * <Location /server-status>
  23.  * SetHandler server-status
  24.  * </Location>
  25.  *
  26.  * You may want to protect this location by password or domain so no one
  27.  * else can look at it.  Then you can access the statistics with a URL like:
  28.  *
  29.  * http://your_server_name/server-status
  30.  *
  31.  * /server-status - Returns page using tables
  32.  * /server-status?notable - Returns page for browsers without table support
  33.  * /server-status?refresh - Returns page with 1 second refresh
  34.  * /server-status?refresh=6 - Returns page with refresh every 6 seconds
  35.  * /server-status?auto - Returns page with data for automatic parsing
  36.  *
  37.  * Mark Cox, [email protected], November 1995
  38.  *
  39.  * 12.11.95 Initial version for www.telescope.org
  40.  * 13.3.96  Updated to remove rprintf's [Mark]
  41.  * 18.3.96  Added CPU usage, process information, and tidied [Ben Laurie]
  42.  * 18.3.96  Make extra Scoreboard variables #definable
  43.  * 25.3.96  Make short report have full precision [Ben Laurie suggested]
  44.  * 25.3.96  Show uptime better [Mark/Ben Laurie]
  45.  * 29.3.96  Better HTML and explanation [Mark/Rob Hartill suggested]
  46.  * 09.4.96  Added message for non-STATUS compiled version
  47.  * 18.4.96  Added per child and per slot counters [Jim Jagielski]
  48.  * 01.5.96  Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
  49.  * 18.5.96  Adapted to use new rprintf() routine, incidentally fixing a missing
  50.  *          piece in short reports [Ben Laurie]
  51.  * 21.5.96  Additional Status codes (DNS and LOGGING only enabled if
  52.  *          extended STATUS is enabled) [George Burgyan/Jim J.]
  53.  * 10.8.98  Allow for extended status info at runtime (no more STATUS)
  54.  *          [Jim J.]
  55.  */
  56.  
  57. #include "httpd.h"
  58. #include "http_config.h"
  59. #include "http_core.h"
  60. #include "http_protocol.h"
  61. #include "http_main.h"
  62. #include "ap_mpm.h"
  63. #include "util_script.h"
  64. #include <time.h>
  65. #include "scoreboard.h"
  66. #include "http_log.h"
  67. #include "mod_status.h"
  68. #if APR_HAVE_UNISTD_H
  69. #include <unistd.h>
  70. #endif
  71. #define APR_WANT_STRFUNC
  72. #include "apr_want.h"
  73. #include "apr_strings.h"
  74.  
  75. #define STATUS_MAXLINE 64
  76.  
  77. #define KBYTE 1024
  78. #define MBYTE 1048576L
  79. #define GBYTE 1073741824L
  80.  
  81. #ifndef DEFAULT_TIME_FORMAT
  82. #define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
  83. #endif
  84.  
  85. #define STATUS_MAGIC_TYPE "application/x-httpd-status"
  86.  
  87. module AP_MODULE_DECLARE_DATA status_module;
  88.  
  89. static int server_limit, thread_limit, threads_per_child, max_servers;
  90.  
  91. /* Implement 'ap_run_status_hook'. */
  92. APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook,
  93.                                     (request_rec *r, int flags),
  94.                                     (r, flags),
  95.                                     OK, DECLINED)
  96.  
  97. #ifdef HAVE_TIMES
  98. /* ugh... need to know if we're running with a pthread implementation
  99.  * such as linuxthreads that treats individual threads as distinct
  100.  * processes; that affects how we add up CPU time in a process
  101.  */
  102. static pid_t child_pid;
  103. #endif
  104.  
  105. /* Format the number of bytes nicely */
  106. static void format_byte_out(request_rec *r, apr_off_t bytes)
  107. {
  108.     if (bytes < (5 * KBYTE))
  109.         ap_rprintf(r, "%d B", (int) bytes);
  110.     else if (bytes < (MBYTE / 2))
  111.         ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
  112.     else if (bytes < (GBYTE / 2))
  113.         ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
  114.     else
  115.         ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
  116. }
  117.  
  118. static void format_kbyte_out(request_rec *r, apr_off_t kbytes)
  119. {
  120.     if (kbytes < KBYTE)
  121.         ap_rprintf(r, "%d kB", (int) kbytes);
  122.     else if (kbytes < MBYTE)
  123.         ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE);
  124.     else
  125.         ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE);
  126. }
  127.  
  128. static void show_time(request_rec *r, apr_interval_time_t tsecs)
  129. {
  130.     int days, hrs, mins, secs;
  131.  
  132.     secs = (int)(tsecs % 60);
  133.     tsecs /= 60;
  134.     mins = (int)(tsecs % 60);
  135.     tsecs /= 60;
  136.     hrs = (int)(tsecs % 24);
  137.     days = (int)(tsecs / 24);
  138.  
  139.     if (days)
  140.         ap_rprintf(r, " %d day%s", days, days == 1 ? "" : "s");
  141.  
  142.     if (hrs)
  143.         ap_rprintf(r, " %d hour%s", hrs, hrs == 1 ? "" : "s");
  144.  
  145.     if (mins)
  146.         ap_rprintf(r, " %d minute%s", mins, mins == 1 ? "" : "s");
  147.  
  148.     if (secs)
  149.         ap_rprintf(r, " %d second%s", secs, secs == 1 ? "" : "s");
  150. }
  151.  
  152. /* Main handler for x-httpd-status requests */
  153.  
  154. /* ID values for command table */
  155.  
  156. #define STAT_OPT_END     -1
  157. #define STAT_OPT_REFRESH  0
  158. #define STAT_OPT_NOTABLE  1
  159. #define STAT_OPT_AUTO     2
  160.  
  161. struct stat_opt {
  162.     int id;
  163.     const char *form_data_str;
  164.     const char *hdr_out_str;
  165. };
  166.  
  167. static const struct stat_opt status_options[] = /* see #defines above */
  168. {
  169.     {STAT_OPT_REFRESH, "refresh", "Refresh"},
  170.     {STAT_OPT_NOTABLE, "notable", NULL},
  171.     {STAT_OPT_AUTO, "auto", NULL},
  172.     {STAT_OPT_END, NULL, NULL}
  173. };
  174.  
  175. /* add another state for slots above the MaxClients setting */
  176. #define SERVER_DISABLED SERVER_NUM_STATUS
  177. #define MOD_STATUS_NUM_STATUS (SERVER_NUM_STATUS+1)
  178.  
  179. static char status_flags[MOD_STATUS_NUM_STATUS];
  180.  
  181. static int status_handler(request_rec *r)
  182. {
  183.     const char *loc;
  184.     apr_time_t nowtime;
  185.     apr_interval_time_t up_time;
  186.     int j, i, res, written;
  187.     int ready;
  188.     int busy;
  189.     unsigned long count;
  190.     unsigned long lres, my_lres, conn_lres;
  191.     apr_off_t bytes, my_bytes, conn_bytes;
  192.     apr_off_t bcount, kbcount;
  193.     long req_time;
  194.     int short_report;
  195.     int no_table_report;
  196.     worker_score *ws_record;
  197.     process_score *ps_record;
  198.     char *stat_buffer;
  199.     pid_t *pid_buffer, worker_pid;
  200.     clock_t tu, ts, tcu, tcs;
  201.     ap_generation_t mpm_generation, worker_generation;
  202. #ifdef HAVE_TIMES
  203.     float tick;
  204.     int times_per_thread;
  205. #endif
  206.  
  207.     if (strcmp(r->handler, STATUS_MAGIC_TYPE) && strcmp(r->handler,
  208.             "server-status")) {
  209.         return DECLINED;
  210.     }
  211.  
  212. #ifdef HAVE_TIMES
  213.     times_per_thread = getpid() != child_pid;
  214. #endif
  215.  
  216.     ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
  217.  
  218. #ifdef HAVE_TIMES
  219. #ifdef _SC_CLK_TCK
  220.     tick = sysconf(_SC_CLK_TCK);
  221. #else
  222.     tick = HZ;
  223. #endif
  224. #endif
  225.  
  226.     ready = 0;
  227.     busy = 0;
  228.     count = 0;
  229.     bcount = 0;
  230.     kbcount = 0;
  231.     short_report = 0;
  232.     no_table_report = 0;
  233.  
  234.     pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t));
  235.     stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
  236.  
  237.     nowtime = apr_time_now();
  238.     tu = ts = tcu = tcs = 0;
  239.  
  240.     if (!ap_exists_scoreboard_image()) {
  241.         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  242.                       "Server status unavailable in inetd mode");
  243.         return HTTP_INTERNAL_SERVER_ERROR;
  244.     }
  245.  
  246.     r->allowed = (AP_METHOD_BIT << M_GET);
  247.     if (r->method_number != M_GET)
  248.         return DECLINED;
  249.  
  250.     ap_set_content_type(r, "text/html; charset=ISO-8859-1");
  251.  
  252.     /*
  253.      * Simple table-driven form data set parser that lets you alter the header
  254.      */
  255.  
  256.     if (r->args) {
  257.         i = 0;
  258.         while (status_options[i].id != STAT_OPT_END) {
  259.             if ((loc = ap_strstr_c(r->args,
  260.                                    status_options[i].form_data_str)) != NULL) {
  261.                 switch (status_options[i].id) {
  262.                 case STAT_OPT_REFRESH: {
  263.                     apr_size_t len = strlen(status_options[i].form_data_str);
  264.                     long t = 0;
  265.  
  266.                     if (*(loc + len ) == '=') {
  267.                         t = atol(loc + len + 1);
  268.                     }
  269.                     apr_table_set(r->headers_out,
  270.                                   status_options[i].hdr_out_str,
  271.                                   apr_ltoa(r->pool, t < 1 ? 10 : t));
  272.                     break;
  273.                 }
  274.                 case STAT_OPT_NOTABLE:
  275.                     no_table_report = 1;
  276.                     break;
  277.                 case STAT_OPT_AUTO:
  278.                     ap_set_content_type(r, "text/plain; charset=ISO-8859-1");
  279.                     short_report = 1;
  280.                     break;
  281.                 }
  282.             }
  283.  
  284.             i++;
  285.         }
  286.     }
  287.  
  288.     for (i = 0; i < server_limit; ++i) {
  289. #ifdef HAVE_TIMES
  290.         clock_t proc_tu = 0, proc_ts = 0, proc_tcu = 0, proc_tcs = 0;
  291.         clock_t tmp_tu, tmp_ts, tmp_tcu, tmp_tcs;
  292. #endif
  293.  
  294.         ps_record = ap_get_scoreboard_process(i);
  295.         for (j = 0; j < thread_limit; ++j) {
  296.             int indx = (i * thread_limit) + j;
  297.  
  298.             ws_record = ap_get_scoreboard_worker_from_indexes(i, j);
  299.             res = ws_record->status;
  300.  
  301.             if ((i >= max_servers || j >= threads_per_child)
  302.                 && (res == SERVER_DEAD))
  303.                 stat_buffer[indx] = status_flags[SERVER_DISABLED];
  304.             else
  305.                 stat_buffer[indx] = status_flags[res];
  306.  
  307.             if (!ps_record->quiescing
  308.                 && ps_record->pid) {
  309.                 if (res == SERVER_READY
  310.                     && ps_record->generation == mpm_generation)
  311.                     ready++;
  312.                 else if (res != SERVER_DEAD &&
  313.                          res != SERVER_STARTING &&
  314.                          res != SERVER_IDLE_KILL)
  315.                     busy++;
  316.             }
  317.  
  318.             /* XXX what about the counters for quiescing/seg faulted
  319.              * processes?  should they be counted or not?  GLA
  320.              */
  321.             if (ap_extended_status) {
  322.                 lres = ws_record->access_count;
  323.                 bytes = ws_record->bytes_served;
  324.  
  325.                 if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) {
  326. #ifdef HAVE_TIMES
  327.                     tmp_tu = ws_record->times.tms_utime;
  328.                     tmp_ts = ws_record->times.tms_stime;
  329.                     tmp_tcu = ws_record->times.tms_cutime;
  330.                     tmp_tcs = ws_record->times.tms_cstime;
  331.  
  332.                     if (times_per_thread) {
  333.                         proc_tu += tmp_tu;
  334.                         proc_ts += tmp_ts;
  335.                         proc_tcu += tmp_tcu;
  336.                         proc_tcs += proc_tcs;
  337.                     }
  338.                     else {
  339.                         if (tmp_tu > proc_tu ||
  340.                             tmp_ts > proc_ts ||
  341.                             tmp_tcu > proc_tcu ||
  342.                             tmp_tcs > proc_tcs) {
  343.                             proc_tu = tmp_tu;
  344.                             proc_ts = tmp_ts;
  345.                             proc_tcu = tmp_tcu;
  346.                             proc_tcs = proc_tcs;
  347.                         }
  348.                     }
  349. #endif /* HAVE_TIMES */
  350.  
  351.                     count += lres;
  352.                     bcount += bytes;
  353.  
  354.                     if (bcount >= KBYTE) {
  355.                         kbcount += (bcount >> 10);
  356.                         bcount = bcount & 0x3ff;
  357.                     }
  358.                 }
  359.             }
  360.         }
  361. #ifdef HAVE_TIMES
  362.         tu += proc_tu;
  363.         ts += proc_ts;
  364.         tcu += proc_tcu;
  365.         tcs += proc_tcs;
  366. #endif
  367.         pid_buffer[i] = ps_record->pid;
  368.     }
  369.  
  370.     /* up_time in seconds */
  371.     up_time = (apr_uint32_t) apr_time_sec(nowtime -
  372.                                ap_scoreboard_image->global->restart_time);
  373.  
  374.     if (!short_report) {
  375.         ap_rputs(DOCTYPE_HTML_3_2
  376.                  "<html><head>\n<title>Apache Status</title>\n</head><body>\n",
  377.                  r);
  378.         ap_rputs("<h1>Apache Server Status for ", r);
  379.         ap_rvputs(r, ap_get_server_name(r), " (via ", r->connection->local_ip,
  380.                   ")</h1>\n\n", NULL);
  381.         ap_rvputs(r, "<dl><dt>Server Version: ",
  382.                   ap_get_server_description(), "</dt>\n", NULL);
  383.         ap_rvputs(r, "<dt>Server Built: ",
  384.                   ap_get_server_built(), "\n</dt></dl><hr /><dl>\n", NULL);
  385.         ap_rvputs(r, "<dt>Current Time: ",
  386.                   ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0),
  387.                              "</dt>\n", NULL);
  388.         ap_rvputs(r, "<dt>Restart Time: ",
  389.                   ap_ht_time(r->pool,
  390.                              ap_scoreboard_image->global->restart_time,
  391.                              DEFAULT_TIME_FORMAT, 0),
  392.                   "</dt>\n", NULL);
  393.         ap_rprintf(r, "<dt>Parent Server Config. Generation: %d</dt>\n",
  394.                    ap_state_query(AP_SQ_CONFIG_GEN));
  395.         ap_rprintf(r, "<dt>Parent Server MPM Generation: %d</dt>\n",
  396.                    (int)mpm_generation);
  397.         ap_rputs("<dt>Server uptime: ", r);
  398.         show_time(r, up_time);
  399.         ap_rputs("</dt>\n", r);
  400.     }
  401.  
  402.     if (ap_extended_status) {
  403.         if (short_report) {
  404.             ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %"
  405.                        APR_OFF_T_FMT "\n",
  406.                        count, kbcount);
  407.  
  408. #ifdef HAVE_TIMES
  409.             /* Allow for OS/2 not having CPU stats */
  410.             if (ts || tu || tcu || tcs)
  411.                 ap_rprintf(r, "CPULoad: %g\n",
  412.                            (tu + ts + tcu + tcs) / tick / up_time * 100.);
  413. #endif
  414.  
  415.             ap_rprintf(r, "Uptime: %ld\n", (long) (up_time));
  416.             if (up_time > 0) {
  417.                 ap_rprintf(r, "ReqPerSec: %g\n",
  418.                            (float) count / (float) up_time);
  419.  
  420.                 ap_rprintf(r, "BytesPerSec: %g\n",
  421.                            KBYTE * (float) kbcount / (float) up_time);
  422.             }
  423.             if (count > 0)
  424.                 ap_rprintf(r, "BytesPerReq: %g\n",
  425.                            KBYTE * (float) kbcount / (float) count);
  426.         }
  427.         else { /* !short_report */
  428.             ap_rprintf(r, "<dt>Total accesses: %lu - Total Traffic: ", count);
  429.             format_kbyte_out(r, kbcount);
  430.             ap_rputs("</dt>\n", r);
  431.  
  432. #ifdef HAVE_TIMES
  433.             /* Allow for OS/2 not having CPU stats */
  434.             ap_rprintf(r, "<dt>CPU Usage: u%g s%g cu%g cs%g",
  435.                        tu / tick, ts / tick, tcu / tick, tcs / tick);
  436.  
  437.             if (ts || tu || tcu || tcs)
  438.                 ap_rprintf(r, " - %.3g%% CPU load</dt>\n",
  439.                            (tu + ts + tcu + tcs) / tick / up_time * 100.);
  440. #endif
  441.  
  442.             if (up_time > 0) {
  443.                 ap_rprintf(r, "<dt>%.3g requests/sec - ",
  444.                            (float) count / (float) up_time);
  445.  
  446.                 format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount
  447.                                                    / (float) up_time));
  448.                 ap_rputs("/second - ", r);
  449.             }
  450.  
  451.             if (count > 0) {
  452.                 format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount
  453.                                                    / (float) count));
  454.                 ap_rputs("/request", r);
  455.             }
  456.  
  457.             ap_rputs("</dt>\n", r);
  458.         } /* short_report */
  459.     } /* ap_extended_status */
  460.  
  461.     if (!short_report)
  462.         ap_rprintf(r, "<dt>%d requests currently being processed, "
  463.                       "%d idle workers</dt>\n", busy, ready);
  464.     else
  465.         ap_rprintf(r, "BusyWorkers: %d\nIdleWorkers: %d\n", busy, ready);
  466.  
  467.     /* send the scoreboard 'table' out */
  468.     if (!short_report)
  469.         ap_rputs("</dl><pre>", r);
  470.     else
  471.         ap_rputs("Scoreboard: ", r);
  472.  
  473.     written = 0;
  474.     for (i = 0; i < server_limit; ++i) {
  475.         for (j = 0; j < thread_limit; ++j) {
  476.             int indx = (i * thread_limit) + j;
  477.             if (stat_buffer[indx] != status_flags[SERVER_DISABLED]) {
  478.                 ap_rputc(stat_buffer[indx], r);
  479.                 if ((written % STATUS_MAXLINE == (STATUS_MAXLINE - 1))
  480.                     && !short_report)
  481.                     ap_rputs("\n", r);
  482.                 written++;
  483.             }
  484.         }
  485.     }
  486.  
  487.     if (short_report)
  488.         ap_rputs("\n", r);
  489.     else {
  490.         ap_rputs("</pre>\n", r);
  491.         ap_rputs("<p>Scoreboard Key:<br />\n", r);
  492.         ap_rputs("\"<b><code>_</code></b>\" Waiting for Connection, \n", r);
  493.         ap_rputs("\"<b><code>S</code></b>\" Starting up, \n", r);
  494.         ap_rputs("\"<b><code>R</code></b>\" Reading Request,<br />\n", r);
  495.         ap_rputs("\"<b><code>W</code></b>\" Sending Reply, \n", r);
  496.         ap_rputs("\"<b><code>K</code></b>\" Keepalive (read), \n", r);
  497.         ap_rputs("\"<b><code>D</code></b>\" DNS Lookup,<br />\n", r);
  498.         ap_rputs("\"<b><code>C</code></b>\" Closing connection, \n", r);
  499.         ap_rputs("\"<b><code>L</code></b>\" Logging, \n", r);
  500.         ap_rputs("\"<b><code>G</code></b>\" Gracefully finishing,<br /> \n", r);
  501.         ap_rputs("\"<b><code>I</code></b>\" Idle cleanup of worker, \n", r);
  502.         ap_rputs("\"<b><code>.</code></b>\" Open slot with no current process,<br />\n", r);
  503.         ap_rputs("<p />\n", r);
  504.         if (!ap_extended_status) {
  505.             int j;
  506.             int k = 0;
  507.             ap_rputs("PID Key: <br />\n", r);
  508.             ap_rputs("<pre>\n", r);
  509.             for (i = 0; i < server_limit; ++i) {
  510.                 for (j = 0; j < thread_limit; ++j) {
  511.                     int indx = (i * thread_limit) + j;
  512.  
  513.                     if (stat_buffer[indx] != '.') {
  514.                         ap_rprintf(r, "   %" APR_PID_T_FMT
  515.                                    " in state: %c ", pid_buffer[i],
  516.                                    stat_buffer[indx]);
  517.  
  518.                         if (++k >= 3) {
  519.                             ap_rputs("\n", r);
  520.                             k = 0;
  521.                         } else
  522.                             ap_rputs(",", r);
  523.                     }
  524.                 }
  525.             }
  526.  
  527.             ap_rputs("\n", r);
  528.             ap_rputs("</pre>\n", r);
  529.         }
  530.     }
  531.  
  532.     if (ap_extended_status && !short_report) {
  533.         if (no_table_report)
  534.             ap_rputs("<hr /><h2>Server Details</h2>\n\n", r);
  535.         else
  536.             ap_rputs("\n\n<table border=\"0\"><tr>"
  537.                      "<th>Srv</th><th>PID</th><th>Acc</th>"
  538.                      "<th>M</th>"
  539. #ifdef HAVE_TIMES
  540.                      "<th>CPU\n</th>"
  541. #endif
  542.                      "<th>SS</th><th>Req</th>"
  543.                      "<th>Conn</th><th>Child</th><th>Slot</th>"
  544.                      "<th>Client</th><th>VHost</th>"
  545.                      "<th>Request</th></tr>\n\n", r);
  546.  
  547.         for (i = 0; i < server_limit; ++i) {
  548.             for (j = 0; j < thread_limit; ++j) {
  549.                 ws_record = ap_get_scoreboard_worker_from_indexes(i, j);
  550.  
  551.                 if (ws_record->access_count == 0 &&
  552.                     (ws_record->status == SERVER_READY ||
  553.                      ws_record->status == SERVER_DEAD)) {
  554.                     continue;
  555.                 }
  556.  
  557.                 ps_record = ap_get_scoreboard_process(i);
  558.  
  559.                 if (ws_record->start_time == 0L)
  560.                     req_time = 0L;
  561.                 else
  562.                     req_time = (long)
  563.                         ((ws_record->stop_time -
  564.                           ws_record->start_time) / 1000);
  565.                 if (req_time < 0L)
  566.                     req_time = 0L;
  567.  
  568.                 lres = ws_record->access_count;
  569.                 my_lres = ws_record->my_access_count;
  570.                 conn_lres = ws_record->conn_count;
  571.                 bytes = ws_record->bytes_served;
  572.                 my_bytes = ws_record->my_bytes_served;
  573.                 conn_bytes = ws_record->conn_bytes;
  574.                 if (ws_record->pid) { /* MPM sets per-worker pid and generation */
  575.                     worker_pid = ws_record->pid;
  576.                     worker_generation = ws_record->generation;
  577.                 }
  578.                 else {
  579.                     worker_pid = ps_record->pid;
  580.                     worker_generation = ps_record->generation;
  581.                 }
  582.  
  583.                 if (no_table_report) {
  584.                     if (ws_record->status == SERVER_DEAD)
  585.                         ap_rprintf(r,
  586.                                    "<b>Server %d-%d</b> (-): %d|%lu|%lu [",
  587.                                    i, (int)worker_generation,
  588.                                    (int)conn_lres, my_lres, lres);
  589.                     else
  590.                         ap_rprintf(r,
  591.                                    "<b>Server %d-%d</b> (%"
  592.                                    APR_PID_T_FMT "): %d|%lu|%lu [",
  593.                                    i, (int) worker_generation,
  594.                                    worker_pid,
  595.                                    (int)conn_lres, my_lres, lres);
  596.  
  597.                     switch (ws_record->status) {
  598.                     case SERVER_READY:
  599.                         ap_rputs("Ready", r);
  600.                         break;
  601.                     case SERVER_STARTING:
  602.                         ap_rputs("Starting", r);
  603.                         break;
  604.                     case SERVER_BUSY_READ:
  605.                         ap_rputs("<b>Read</b>", r);
  606.                         break;
  607.                     case SERVER_BUSY_WRITE:
  608.                         ap_rputs("<b>Write</b>", r);
  609.                         break;
  610.                     case SERVER_BUSY_KEEPALIVE:
  611.                         ap_rputs("<b>Keepalive</b>", r);
  612.                         break;
  613.                     case SERVER_BUSY_LOG:
  614.                         ap_rputs("<b>Logging</b>", r);
  615.                         break;
  616.                     case SERVER_BUSY_DNS:
  617.                         ap_rputs("<b>DNS lookup</b>", r);
  618.                         break;
  619.                     case SERVER_CLOSING:
  620.                         ap_rputs("<b>Closing</b>", r);
  621.                         break;
  622.                     case SERVER_DEAD:
  623.                         ap_rputs("Dead", r);
  624.                         break;
  625.                     case SERVER_GRACEFUL:
  626.                         ap_rputs("Graceful", r);
  627.                         break;
  628.                     case SERVER_IDLE_KILL:
  629.                         ap_rputs("Dying", r);
  630.                         break;
  631.                     default:
  632.                         ap_rputs("?STATE?", r);
  633.                         break;
  634.                     }
  635.  
  636.                     ap_rprintf(r, "] "
  637. #ifdef HAVE_TIMES
  638.                                "u%g s%g cu%g cs%g"
  639. #endif
  640.                                "\n %ld %ld (",
  641. #ifdef HAVE_TIMES
  642.                                ws_record->times.tms_utime / tick,
  643.                                ws_record->times.tms_stime / tick,
  644.                                ws_record->times.tms_cutime / tick,
  645.                                ws_record->times.tms_cstime / tick,
  646. #endif
  647.                                (long)apr_time_sec(nowtime -
  648.                                                   ws_record->last_used),
  649.                                (long) req_time);
  650.  
  651.                     format_byte_out(r, conn_bytes);
  652.                     ap_rputs("|", r);
  653.                     format_byte_out(r, my_bytes);
  654.                     ap_rputs("|", r);
  655.                     format_byte_out(r, bytes);
  656.                     ap_rputs(")\n", r);
  657.                     ap_rprintf(r,
  658.                                " <i>%s {%s}</i> <b>[%s]</b><br />\n\n",
  659.                                ap_escape_html(r->pool,
  660.                                               ws_record->client),
  661.                                ap_escape_html(r->pool,
  662.                                               ap_escape_logitem(r->pool,
  663.                                                                 ws_record->request)),
  664.                                ap_escape_html(r->pool,
  665.                                               ws_record->vhost));
  666.                 }
  667.                 else { /* !no_table_report */
  668.                     if (ws_record->status == SERVER_DEAD)
  669.                         ap_rprintf(r,
  670.                                    "<tr><td><b>%d-%d</b></td><td>-</td><td>%d/%lu/%lu",
  671.                                    i, (int)worker_generation,
  672.                                    (int)conn_lres, my_lres, lres);
  673.                     else
  674.                         ap_rprintf(r,
  675.                                    "<tr><td><b>%d-%d</b></td><td>%"
  676.                                    APR_PID_T_FMT
  677.                                    "</td><td>%d/%lu/%lu",
  678.                                    i, (int)worker_generation,
  679.                                    worker_pid,
  680.                                    (int)conn_lres,
  681.                                    my_lres, lres);
  682.  
  683.                     switch (ws_record->status) {
  684.                     case SERVER_READY:
  685.                         ap_rputs("</td><td>_", r);
  686.                         break;
  687.                     case SERVER_STARTING:
  688.                         ap_rputs("</td><td><b>S</b>", r);
  689.                         break;
  690.                     case SERVER_BUSY_READ:
  691.                         ap_rputs("</td><td><b>R</b>", r);
  692.                         break;
  693.                     case SERVER_BUSY_WRITE:
  694.                         ap_rputs("</td><td><b>W</b>", r);
  695.                         break;
  696.                     case SERVER_BUSY_KEEPALIVE:
  697.                         ap_rputs("</td><td><b>K</b>", r);
  698.                         break;
  699.                     case SERVER_BUSY_LOG:
  700.                         ap_rputs("</td><td><b>L</b>", r);
  701.                         break;
  702.                     case SERVER_BUSY_DNS:
  703.                         ap_rputs("</td><td><b>D</b>", r);
  704.                         break;
  705.                     case SERVER_CLOSING:
  706.                         ap_rputs("</td><td><b>C</b>", r);
  707.                         break;
  708.                     case SERVER_DEAD:
  709.                         ap_rputs("</td><td>.", r);
  710.                         break;
  711.                     case SERVER_GRACEFUL:
  712.                         ap_rputs("</td><td>G", r);
  713.                         break;
  714.                     case SERVER_IDLE_KILL:
  715.                         ap_rputs("</td><td>I", r);
  716.                         break;
  717.                     default:
  718.                         ap_rputs("</td><td>?", r);
  719.                         break;
  720.                     }
  721.  
  722.                     ap_rprintf(r,
  723.                                "\n</td>"
  724. #ifdef HAVE_TIMES
  725.                                "<td>%.2f</td>"
  726. #endif
  727.                                "<td>%ld</td><td>%ld",
  728. #ifdef HAVE_TIMES
  729.                                (ws_record->times.tms_utime +
  730.                                 ws_record->times.tms_stime +
  731.                                 ws_record->times.tms_cutime +
  732.                                 ws_record->times.tms_cstime) / tick,
  733. #endif
  734.                                (long)apr_time_sec(nowtime -
  735.                                                   ws_record->last_used),
  736.                                (long)req_time);
  737.  
  738.                     ap_rprintf(r, "</td><td>%-1.1f</td><td>%-2.2f</td><td>%-2.2f\n",
  739.                                (float)conn_bytes / KBYTE, (float) my_bytes / MBYTE,
  740.                                (float)bytes / MBYTE);
  741.  
  742.                     ap_rprintf(r, "</td><td>%s</td><td nowrap>%s</td>"
  743.                                   "<td nowrap>%s</td></tr>\n\n",
  744.                                ap_escape_html(r->pool,
  745.                                               ws_record->client),
  746.                                ap_escape_html(r->pool,
  747.                                               ws_record->vhost),
  748.                                ap_escape_html(r->pool,
  749.                                               ap_escape_logitem(r->pool,
  750.                                                       ws_record->request)));
  751.                 } /* no_table_report */
  752.             } /* for (j...) */
  753.         } /* for (i...) */
  754.  
  755.         if (!no_table_report) {
  756.             ap_rputs("</table>\n \
  757. <hr /> \
  758. <table>\n \
  759. <tr><th>Srv</th><td>Child Server number - generation</td></tr>\n \
  760. <tr><th>PID</th><td>OS process ID</td></tr>\n \
  761. <tr><th>Acc</th><td>Number of accesses this connection / this child / this slot</td></tr>\n \
  762. <tr><th>M</th><td>Mode of operation</td></tr>\n"
  763.  
  764. #ifdef HAVE_TIMES
  765. "<tr><th>CPU</th><td>CPU usage, number of seconds</td></tr>\n"
  766. #endif
  767.  
  768. "<tr><th>SS</th><td>Seconds since beginning of most recent request</td></tr>\n \
  769. <tr><th>Req</th><td>Milliseconds required to process most recent request</td></tr>\n \
  770. <tr><th>Conn</th><td>Kilobytes transferred this connection</td></tr>\n \
  771. <tr><th>Child</th><td>Megabytes transferred this child</td></tr>\n \
  772. <tr><th>Slot</th><td>Total megabytes transferred this slot</td></tr>\n \
  773. </table>\n", r);
  774.         }
  775.     } /* if (ap_extended_status && !short_report) */
  776.     else {
  777.  
  778.         if (!short_report) {
  779.             ap_rputs("<hr />To obtain a full report with current status "
  780.                      "information you need to use the "
  781.                      "<code>ExtendedStatus On</code> directive.\n", r);
  782.         }
  783.     }
  784.  
  785.     {
  786.         /* Run extension hooks to insert extra content. */
  787.         int flags =
  788.             (short_report ? AP_STATUS_SHORT : 0) |
  789.             (no_table_report ? AP_STATUS_NOTABLE : 0) |
  790.             (ap_extended_status ? AP_STATUS_EXTENDED : 0);
  791.  
  792.         ap_run_status_hook(r, flags);
  793.     }
  794.  
  795.     if (!short_report) {
  796.         ap_rputs(ap_psignature("<hr />\n",r), r);
  797.         ap_rputs("</body></html>\n", r);
  798.     }
  799.  
  800.     return 0;
  801. }
  802.  
  803. static int status_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
  804. {
  805.     /* When mod_status is loaded, default our ExtendedStatus to 'on'
  806.      * other modules which prefer verbose scoreboards may play a similar game.
  807.      * If left to their own requirements, mpm modules can make do with simple
  808.      * scoreboard entries.
  809.      */
  810.     ap_extended_status = 1;
  811.     return OK;
  812. }
  813.  
  814. static int status_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
  815.                        server_rec *s)
  816. {
  817.     status_flags[SERVER_DEAD] = '.';  /* We don't want to assume these are in */
  818.     status_flags[SERVER_READY] = '_'; /* any particular order in scoreboard.h */
  819.     status_flags[SERVER_STARTING] = 'S';
  820.     status_flags[SERVER_BUSY_READ] = 'R';
  821.     status_flags[SERVER_BUSY_WRITE] = 'W';
  822.     status_flags[SERVER_BUSY_KEEPALIVE] = 'K';
  823.     status_flags[SERVER_BUSY_LOG] = 'L';
  824.     status_flags[SERVER_BUSY_DNS] = 'D';
  825.     status_flags[SERVER_CLOSING] = 'C';
  826.     status_flags[SERVER_GRACEFUL] = 'G';
  827.     status_flags[SERVER_IDLE_KILL] = 'I';
  828.     status_flags[SERVER_DISABLED] = ' ';
  829.     ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
  830.     ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
  831.     ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
  832.     /* work around buggy MPMs */
  833.     if (threads_per_child == 0)
  834.         threads_per_child = 1;
  835.     ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_servers);
  836.     return OK;
  837. }
  838.  
  839. #ifdef HAVE_TIMES
  840. static void status_child_init(apr_pool_t *p, server_rec *s)
  841. {
  842.     child_pid = getpid();
  843. }
  844. #endif
  845.  
  846. static void register_hooks(apr_pool_t *p)
  847. {
  848.     ap_hook_handler(status_handler, NULL, NULL, APR_HOOK_MIDDLE);
  849.     ap_hook_pre_config(status_pre_config, NULL, NULL, APR_HOOK_LAST);
  850.     ap_hook_post_config(status_init, NULL, NULL, APR_HOOK_MIDDLE);
  851. #ifdef HAVE_TIMES
  852.     ap_hook_child_init(status_child_init, NULL, NULL, APR_HOOK_MIDDLE);
  853. #endif
  854. }
  855.  
  856. AP_DECLARE_MODULE(status) =
  857. {
  858.     STANDARD20_MODULE_STUFF,
  859.     NULL,                       /* dir config creater */
  860.     NULL,                       /* dir merger --- default is to override */
  861.     NULL,                       /* server config */
  862.     NULL,                       /* merge server config */
  863.     NULL,                       /* command table */
  864.     register_hooks              /* register_hooks */
  865. };
Advertisement
Add Comment
Please, Sign In to add comment