Apache response_counters Patch The MIT License (c)2007 Brian Shire & Facbeook Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Give extra counter information regarding different return codes from Apache on the server status page. To use: Apply the patch with the following commands: cd apache-1.3.x patch -p1 -i ap_response_counters.patch You may need to define AP_STATUS_NO_ASM to exclude possibly system specific assembly. Provide feedback to diff --git a/src/include/scoreboard.h b/src/include/scoreboard.h index 67b56b6..549a6df 100644 --- a/src/include/scoreboard.h +++ b/src/include/scoreboard.h @@ -97,6 +97,9 @@ typedef struct { #endif unsigned char status; unsigned long access_count; + /**** BEGIN Patch: response_counters ***/ + unsigned int status_response_codes[RESPONSE_CODES]; + /**** END Patch: response_counters ***/ unsigned long bytes_served; unsigned long my_access_count; unsigned long my_bytes_served; diff --git a/src/main/http_protocol.c b/src/main/http_protocol.c index cd370fc..1ea433f 100644 --- a/src/main/http_protocol.c +++ b/src/main/http_protocol.c @@ -1521,6 +1521,8 @@ static const char * const status_lines[RESPONSE_CODES] = "510 Not Extended" }; +API_EXPORT(const char*) ap_status_line(int status) { return status_lines[status]; } + /* The index is found by its offset from the x00 code of each level. * Although this is fast, it will need to be replaced if some nutcase * decides to define a high-numbered code before the lower numbers. diff --git a/src/modules/standard/mod_status.c b/src/modules/standard/mod_status.c index 526b194..029a8ce 100644 --- a/src/modules/standard/mod_status.c +++ b/src/modules/standard/mod_status.c @@ -162,6 +162,7 @@ static void show_time(request_rec *r, time_t tsecs) #define STAT_OPT_REFRESH 0 #define STAT_OPT_NOTABLE 1 #define STAT_OPT_AUTO 2 +#define STAT_OPT_RESET_RESPONSE_COUNTS 3 struct stat_opt { int id; @@ -174,6 +175,7 @@ static const struct stat_opt status_options[] = /* see #defines above */ {STAT_OPT_REFRESH, "refresh", "Refresh"}, {STAT_OPT_NOTABLE, "notable", NULL}, {STAT_OPT_AUTO, "auto", NULL}, + {STAT_OPT_RESET_RESPONSE_COUNTS, "reset_response_counts", NULL}, {STAT_OPT_END, NULL, NULL} }; @@ -184,13 +186,16 @@ static int status_handler(request_rec *r) char *loc; time_t nowtime = time(NULL); time_t up_time; - int i, res; + int i, i2, res; int ready = 0; int busy = 0; unsigned long count = 0; unsigned long lres, bytes; unsigned long my_lres, my_bytes, conn_bytes; unsigned short conn_lres; + /**** BEGIN Patch: response_counters ***/ + unsigned int status_response_codes[RESPONSE_CODES] = {0}; + /**** END Patch: response_counters ***/ unsigned long bcount = 0; unsigned long kbcount = 0; long req_time; @@ -202,6 +207,7 @@ static int status_handler(request_rec *r) #endif #endif int short_report = 0; + int reset_response_counts = 0; int no_table_report = 0; short_score score_record; parent_score ps_record; @@ -250,6 +256,9 @@ static int status_handler(request_rec *r) r->content_type = "text/plain; charset=ISO-8859-1"; short_report = 1; break; + case STAT_OPT_RESET_RESPONSE_COUNTS: + reset_response_counts=1; + break; } } i++; @@ -277,6 +286,14 @@ static int status_handler(request_rec *r) else if (res != SERVER_DEAD) busy++; if (ap_extended_status) { + /**** BEGIN Patch: response_counters ***/ + for(i2=0; i2 < RESPONSE_CODES; i2++) { + status_response_codes[i2] += score_record.status_response_codes[i2]; + if(reset_response_counts) { + ap_scoreboard_image->servers[i].status_response_codes[i2] = 0; + } + } + /**** END Patch: response_counters ***/ lres = score_record.access_count; bytes = score_record.bytes_served; if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) { @@ -698,6 +715,25 @@ static int status_handler(request_rec *r) #endif } + /**** BEGIN Patch: response_counters ***/ + { + unsigned int i; + if(!short_report) { + ap_rputs("\n
\n
Response Code Counts:

\n\n", r); + ap_rputs("", r); + for(i=0; i < RESPONSE_CODES; i++) { + ap_rprintf(r, "\n", ap_status_line(i), status_response_codes[i]); + } + ap_rputs("
%s:    %d
", r); + } else { + for(i=0; i < RESPONSE_CODES; i++) { + ap_rprintf(r, "%s: %d\n", ap_status_line(i), status_response_codes[i]); + } + } + } + /**** END Patch: response_counters ***/ + + } else { if (!short_report) { @@ -737,6 +773,48 @@ static const handler_rec status_handlers[] = {NULL} }; + +/**** BEGIN Patch: response_counters ***/ +static int status_log_transaction(request_rec *r) { + unsigned int index; + unsigned int* ptr; + unsigned int old; + unsigned int new; + unsigned int prev; + +#if 1 /* Exclude this if you don't need the cost of this check, but would be needed to be "correct" */ + if (!ap_exists_scoreboard_image()) { + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "Server status unavailable in inetd mode"); + return OK; + } +#endif + +#ifndef AP_STATUS_NO_ASM + index = ap_index_of_response(r->status); + ptr = &ap_scoreboard_image->servers[r->connection->child_num].status_response_codes[index]; + old = *ptr; + new = old + 1; + asm volatile("LOCK cmpxchgl %[new], %[ptr]" + : "=a" (prev) + : [new] "r" (new), + [ptr] "m" (*ptr), + [old] "0" (old) + : "memory", "cc" + ); + if(old != prev) { + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "cmpxchg failed on status response code (mod_status) (this only affects apache statisticts, see Brian Shire for details."); + } +#else + ap_scoreboard_image->servers[r->connection->child_num].status_response_codes[ap_index_of_response(r->status)]++; +#endif + + //ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "In log_transaction %d %d", r->connection->child_num, ap_index_of_response(r->status)); + + return OK; +} +/**** END Patch: response_counters ***/ + + module MODULE_VAR_EXPORT status_module = { STANDARD_MODULE_STUFF, @@ -753,7 +831,7 @@ module MODULE_VAR_EXPORT status_module = NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ - NULL, /* logger */ + status_log_transaction, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */