mod_status.c revision a72ba68ecbbc61e4b513e50d6000245c33f753dc
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz/* Licensed to the Apache Software Foundation (ASF) under one or more
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * contributor license agreements. See the NOTICE file distributed with
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * this work for additional information regarding copyright ownership.
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * The ASF licenses this file to You under the Apache License, Version 2.0
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * (the "License"); you may not use this file except in compliance with
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * the License. You may obtain a copy of the License at
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * Unless required by applicable law or agreed to in writing, software
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * distributed under the License is distributed on an "AS IS" BASIS,
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * See the License for the specific language governing permissions and
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * limitations under the License.
e9f0cd6ee7be0336cfd071df0451d6282cf55d75Ewaryst Schulz/* Status Module. Display lots of internal data about how Apache is
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * performing and the state of all children processes.
a3b8d685ae08bf3f83a6c2930e872183c487c844Ewaryst Schulz * To enable this, add the following lines into any config file:
a3b8d685ae08bf3f83a6c2930e872183c487c844Ewaryst Schulz * <Location /server-status>
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * SetHandler server-status
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * </Location>
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * You may want to protect this location by password or domain so no one
7af4df794a0e0f0cb927bd9371556ad098308983Ewaryst Schulz * else can look at it. Then you can access the statistics with a URL like:
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * /server-status - Returns page using tables
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * /server-status?notable - Returns page for browsers without table support
a3b8d685ae08bf3f83a6c2930e872183c487c844Ewaryst Schulz * /server-status?refresh - Returns page with 1 second refresh
a3b8d685ae08bf3f83a6c2930e872183c487c844Ewaryst Schulz * /server-status?refresh=6 - Returns page with refresh every 6 seconds
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz * /server-status?auto - Returns page with data for automatic parsing
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * Mark Cox, mark@ukweb.com, November 1995
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 12.11.95 Initial version for www.telescope.org
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 13.3.96 Updated to remove rprintf's [Mark]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 18.3.96 Added CPU usage, process information, and tidied [Ben Laurie]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 18.3.96 Make extra Scoreboard variables #definable
a3b8d685ae08bf3f83a6c2930e872183c487c844Ewaryst Schulz * 25.3.96 Make short report have full precision [Ben Laurie suggested]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 25.3.96 Show uptime better [Mark/Ben Laurie]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 29.3.96 Better HTML and explanation [Mark/Rob Hartill suggested]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 09.4.96 Added message for non-STATUS compiled version
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 18.4.96 Added per child and per slot counters [Jim Jagielski]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 01.5.96 Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 18.5.96 Adapted to use new rprintf() routine, incidentally fixing a missing
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * piece in short reports [Ben Laurie]
a3b8d685ae08bf3f83a6c2930e872183c487c844Ewaryst Schulz * 21.5.96 Additional Status codes (DNS and LOGGING only enabled if
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz * extended STATUS is enabled) [George Burgyan/Jim J.]
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * 10.8.98 Allow for extended status info at runtime (no more STATUS)
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz#endif /* NEXT */
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz#define STATUS_MAGIC_TYPE "application/x-httpd-status"
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz/* Implement 'ap_run_status_hook'. */
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst SchulzAPR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook,
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz/* ugh... need to know if we're running with a pthread implementation
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz * such as linuxthreads that treats individual threads as distinct
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz * processes; that affects how we add up CPU time in a process
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz * command-related code. This is here to prevent use of ExtendedStatus
e9f0cd6ee7be0336cfd071df0451d6282cf55d75Ewaryst Schulz * without status_module included.
e9f0cd6ee7be0336cfd071df0451d6282cf55d75Ewaryst Schulzstatic const char *set_extended_status(cmd_parms *cmd, void *dummy, int arg)
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulzstatic const command_rec status_module_cmds[] =
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz AP_INIT_FLAG("ExtendedStatus", set_extended_status, NULL, RSRC_CONF,
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz "\"On\" to enable extended status information, \"Off\" to disable"),
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz/* Format the number of bytes nicely */
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulzstatic void format_byte_out(request_rec *r, apr_off_t bytes)
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulzstatic void format_kbyte_out(request_rec *r, apr_off_t kbytes)
6c3ce177a0ad551edaae7daa17772b12f77a86daEwaryst Schulz ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE);
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE);
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulzstatic void show_time(request_rec *r, apr_interval_time_t tsecs)
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz ap_rprintf(r, " %d day%s", days, days == 1 ? "" : "s");
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz ap_rprintf(r, " %d hour%s", hrs, hrs == 1 ? "" : "s");
6c3ce177a0ad551edaae7daa17772b12f77a86daEwaryst Schulz ap_rprintf(r, " %d minute%s", mins, mins == 1 ? "" : "s");
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz ap_rprintf(r, " %d second%s", secs, secs == 1 ? "" : "s");
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz/* Main handler for x-httpd-status requests */
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz/* ID values for command table */
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulzstatic const struct stat_opt status_options[] = /* see #defines above */
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz unsigned long count;
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz int times_per_thread = getpid() != child_pid;
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t));
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
f31eef72d6536eeb5a51e86d1f367cbb1a1b8e06Ewaryst Schulz "Server status unavailable in inetd mode");
f31eef72d6536eeb5a51e86d1f367cbb1a1b8e06Ewaryst Schulz ap_set_content_type(r, "text/html; charset=ISO-8859-1");
213ff2bc64713dccda8de3db300ba188bd585866Ewaryst Schulz * Simple table-driven form data set parser that lets you alter the header
213ff2bc64713dccda8de3db300ba188bd585866Ewaryst Schulz while (status_options[i].id != STAT_OPT_END) {
e9f0cd6ee7be0336cfd071df0451d6282cf55d75Ewaryst Schulz if (*(loc + strlen(status_options[i].form_data_str)) == '='
e9f0cd6ee7be0336cfd071df0451d6282cf55d75Ewaryst Schulz && atol(loc + strlen(status_options[i].form_data_str)
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz ap_set_content_type(r, "text/plain; charset=ISO-8859-1");
213ff2bc64713dccda8de3db300ba188bd585866Ewaryst Schulz for (i = 0; i < server_limit; ++i) {
7594b91154e299c9bcecd2bd62698705b55f99e8Ewaryst Schulz clock_t proc_tu = 0, proc_ts = 0, proc_tcu = 0, proc_tcs = 0;
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz for (j = 0; j < thread_limit; ++j) {
6c3ce177a0ad551edaae7daa17772b12f77a86daEwaryst Schulz ws_record = ap_get_scoreboard_worker_from_indexes(i, j);
f474203c4cef7d85cb078f15ce5c2cea71e9a030Ewaryst Schulz && ps_record->generation == ap_my_generation)
6c3ce177a0ad551edaae7daa17772b12f77a86daEwaryst Schulz /* XXX what about the counters for quiescing/seg faulted
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz * processes? should they be counted or not? GLA
f54cad0338da90c6789bb9baae1caec50d994b3aEwaryst Schulz if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) {
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz#endif /* HAVE_TIMES */
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz /* up_time in seconds */
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz up_time = (apr_uint32_t) apr_time_sec(nowtime -
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz "<html><head>\n<title>Apache Status</title>\n</head><body>\n",
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz ap_rputs("<h1>Apache Server Status for ", r);
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz ap_rvputs(r, ap_get_server_name(r), "</h1>\n\n", NULL);
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz ap_get_server_description(), "</dt>\n", NULL);
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz ap_get_server_built(), "\n</dt></dl><hr /><dl>\n", NULL);
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0),
67f09e0fddea50c48620c011b6d001cffe565de6Ewaryst Schulz ap_rprintf(r, "<dt>Parent Server Generation: %d</dt>\n",
6c3ce177a0ad551edaae7daa17772b12f77a86daEwaryst Schulz ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %"
6c3ce177a0ad551edaae7daa17772b12f77a86daEwaryst Schulz /* Allow for OS/2 not having CPU stats */
if (up_time > 0) {
if (count > 0)
#ifdef HAVE_TIMES
if (up_time > 0) {
/ (float) up_time));
if (count > 0) {
/ (float) count));
if (!short_report)
if (!short_report)
for (i = 0; i < server_limit; ++i) {
for (j = 0; j < thread_limit; ++j) {
&& !short_report)
if (short_report)
if (!ap_extended_status) {
for (i = 0; i < server_limit; ++i) {
for (j = 0; j < thread_limit; ++j) {
if (no_table_report)
#ifdef HAVE_TIMES
for (i = 0; i < server_limit; ++i) {
for (j = 0; j < thread_limit; ++j) {
req_time = 0L;
req_time = (long)
if (req_time < 0L)
req_time = 0L;
if (no_table_report) {
ap_rprintf(r,
i, (int)worker_generation,
ap_rprintf(r,
i, (int) worker_generation,
case SERVER_READY:
case SERVER_STARTING:
case SERVER_BUSY_READ:
case SERVER_BUSY_WRITE:
case SERVER_BUSY_KEEPALIVE:
case SERVER_BUSY_LOG:
case SERVER_BUSY_DNS:
case SERVER_CLOSING:
case SERVER_DEAD:
case SERVER_GRACEFUL:
case SERVER_IDLE_KILL:
#ifdef HAVE_TIMES
#ifdef HAVE_TIMES
(long) req_time);
ap_rprintf(r,
ap_rprintf(r,
i, (int)worker_generation,
ap_rprintf(r,
i, (int)worker_generation,
(int)conn_lres,
case SERVER_READY:
case SERVER_STARTING:
case SERVER_BUSY_READ:
case SERVER_BUSY_WRITE:
case SERVER_BUSY_KEEPALIVE:
case SERVER_BUSY_LOG:
case SERVER_BUSY_DNS:
case SERVER_CLOSING:
case SERVER_DEAD:
case SERVER_GRACEFUL:
case SERVER_IDLE_KILL:
ap_rprintf(r,
#ifdef HAVE_TIMES
#ifdef HAVE_TIMES
(long)req_time);
ap_rprintf(r,
ap_rprintf(r,
if (!no_table_report) {
#ifdef HAVE_TIMES
if (!short_report) {
int flags =
if (!short_report) {
server_rec *s)
return OK;
#ifdef HAVE_TIMES
#ifdef HAVE_TIMES