The following patch implements the get_mgmt_items hook in the scoreboard
(PRELIM)
I have included the patch inline -- as well as a attachment.
I have also include a module (destined for the experimental directory)
which will show the
results (in HTML & XML format)
to use add the following in httpd.conf:
<Location /mgmt-status>
SetHandler mgmt-status
</Location
then http://server/mgmt-status/?scoreboard.current.summary
to show the summary table
or
http://server/mgmt-status/?scorebaord.current.summary.status.waiting
to show the number of threads waiting
or
http://server/mgmt-status/?scoreboard.current.worker.*.thread.*.status
to show each individual thread's status
It still needs a bit of work, but it is ready for you guys to rip it
apart.
--Ian
Index: scoreboard.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/scoreboard.c,v
retrieving revision 1.24
diff -u -r1.24 scoreboard.c
--- scoreboard.c 2001/05/22 01:31:12 1.24
+++ scoreboard.c 2001/06/18 22:40:57
@@ -88,6 +88,416 @@
#include "apr_shmem.h"
static apr_shmem_t *scoreboard_shm = NULL;
#endif
+
+/*
+ * Sets a individual detail level for a given child/thread pair
+ *
+ */
+struct server_status_desc {
+ char id;
+ const char*key;
+ const char *description;
+};
+
+static const struct server_status_desc server_status_desc[] = {
+ {SERVER_DEAD, "dead", "Server Dead"},
+ {SERVER_STARTING, "starting", "Server Starting Up"},
+ {SERVER_READY, "waiting", "Waiting for
connection"},
+ {SERVER_BUSY_READ, "reading", "Reading a client
request"},
+ {SERVER_BUSY_WRITE, "writing", "Processing a client
request"},
+ {SERVER_BUSY_KEEPALIVE,"keepalive", "Waiting for more
requests via keepalive"},
+ {SERVER_BUSY_LOG, "log", "Logging the Request"},
+ {SERVER_BUSY_DNS, "dns", "Looking up a
hostname"},
+ {SERVER_GRACEFUL, "gracefull","server is gracefully
finishing request"},
+ {SERVER_ACCEPTING, "accepting","thread is accepting
connections"},
+ {SERVER_QUEUEING, "queueing", "thread is putting
connection on the queue"},
+ {SERVER_IDLE_KILL, "idlekill", "Server is cleaning up
idle children"},
+ {-1, "unknown","unknown/invalid key"}
+};
+
+/*
+ * TODO: move helper functions out of scoreboard
+ * mgmt_set_mgmt_long -- sets a line which represents a 'long'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_long(apr_pool_t *p, const
char*name, const char*desc,long val)
+{
+ ap_mgmt_item_t* h;
+ h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+ h->name= name;
+ h->description = desc;
+ h->vtype= ap_mgmt_type_long;
+ h->v.i_value = val;
+ return h;
+}
+/*
+ * mgmt_set_mgmt_string -- sets a line which represents a 'string'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_string(apr_pool_t *p, const
char*name, const char*desc,const char*val)
+{
+ ap_mgmt_item_t* h;
+ h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+ h->name= name;
+ h->description = desc;
+ h->vtype= ap_mgmt_type_string;
+ h->v.s_value = val;
+ return h;
+}
+/*
+ * mgmt_set_mgmt_hash -- sets a line which represents a group of other
keys
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_hash(apr_pool_t *p, const
char*name, const char*desc,apr_hash_t *val)
+{
+ ap_mgmt_item_t* h;
+ h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+ h->name= name;
+ h->description = desc;
+ h->vtype= ap_mgmt_type_hash;
+ h->v.h_value = val;
+ return h;
+}
+
+/*
+ * get variables related to a individual thread
+ */
+static int mgmt_get_var_current_worker_thread_detail(apr_pool_t *p,
const char*keyPrefix,
+ const char**elements, int level, const int maxLevel, apr_hash_t
*ht,
+ int child_num, int thread_num )
+{
+ int bWantAll=0;
+ worker_score ws_record;
+ ap_mgmt_item_t *h;
+
+ const char*word;
+ if (level >= maxLevel)
+ word=NULL;
+ else {
+ if ( strcmp(elements[level],"*")==0 )
+ word = NULL;
+ else
+ word=elements[level];
+ }
+
+
+ if ( child_num > HARD_SERVER_LIMIT || thread_num >
HARD_THREAD_LIMIT) {
+ return DECLINED;
+ }
+
+ ws_record = ap_scoreboard_image->servers[child_num][thread_num];
+
+ if ( word == NULL || strcmp(word,"thread_num")==0) {
+ h = mgmt_set_mgmt_long(p, "thread_num", "Thread
Number",ws_record.thread_num);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"thread_num",NULL),APR_HASH_KEY_STRING,h);
+ }
+ /* XXX: ?? should be handled by MPM perhaps? or in a
arch-specific call?*/
+#if APR_HAS_THREADS
+ if ( word == NULL || strcmp(word,"tid")==0) {
+ h = mgmt_set_mgmt_long(p, "tid", "Thread ID (OS
Specific)",(long)ws_record.tid);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"tid",NULL),APR_HASH_KEY_STRING,h);
+ }
+#endif
+ if ( word == NULL || strcmp(word,"status")==0) {
+ int i=0;
+ while ( server_status_desc[i].id != -1 &&
+ server_status_desc[i].id !=
ws_record.status) {
+ i++;
+ }
+
+ if (i == -1 ) {
+ h = mgmt_set_mgmt_string(p,
"status","??unknown/invalid status??","??unknown??");
+ } else {
+ h = mgmt_set_mgmt_string(p,
"status",server_status_desc[i].description,server_status_desc[i].key);
+ }
+
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"access_slot")==0) {
+ h = mgmt_set_mgmt_long(p, "access_slot","Access Counts
for this slot",ws_record.access_count);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_slot",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"access_connection")==0) {
+ h = mgmt_set_mgmt_long(p, "access_connection","Access
Counts for this connection",ws_record.conn_count);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_connection",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"access_child")==0) {
+ h = mgmt_set_mgmt_long(p, "access_child","Access Counts
for this child",ws_record.my_access_count);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_child",NULL),APR_HASH_KEY_STRING,h);
+ }
+
+ if ( word == NULL || strcmp(word,"bytes_slot")==0) {
+ h = mgmt_set_mgmt_long(p, "bytes_slot","bytes served for
this slot",ws_record.bytes_served);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_slot",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"bytes_connection")==0) {
+ h = mgmt_set_mgmt_long(p, "bytes_connection","bytes
served for this connection",ws_record.conn_bytes);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_connection",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"bytes_child")==0) {
+ h = mgmt_set_mgmt_long(p, "bytes_child","bytes served
for this child",ws_record.my_bytes_served);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_child",NULL),APR_HASH_KEY_STRING,h);
+ }
+
+ if ( word == NULL || strcmp(word,"request")==0) {
+ h = mgmt_set_mgmt_string(p, "request","the request
currently being processed",apr_pstrdup(p,ws_record.request));
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"request",NULL),APR_HASH_KEY_STRING,h);
+ }
+
+ return OK;
+}
+static int mgmt_get_var_current_worker_child(apr_pool_t *p, const
char*keyPrefix, const char**elements, int level, const int maxLevel,
apr_hash_t *ht, int child )
+{
+ int i;
+ process_score ps_record;
+ const char*word;
+ ap_mgmt_item_t *h;
+
+ if ( child > HARD_SERVER_LIMIT )
+ return DECLINED;
+ ps_record = ap_scoreboard_image->parent[child];
+
+
+
+ if (level >= maxLevel)
+ word=NULL;
+ else {
+ if ( strcmp(elements[level],"*")==0 )
+ word = NULL;
+ else
+ word=elements[level];
+ }
+
+ if ( word == NULL || strcmp(word,"pid")==0) {
+ h = mgmt_set_mgmt_long(p,"pid","Process
ID",ps_record.pid);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"pid",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"generation")==0) {
+ h = mgmt_set_mgmt_long(p,"generation","Process
Generation",ps_record.generation);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"generation",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"type")==0) {
+ h = mgmt_set_mgmt_string(p,"scoreboardType","Scoreboard
Type",
+ (ps_record.sb_type == SB_SHARED)?
"shared":"not shared");
+
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"type",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"status")==0) {
+ h = mgmt_set_mgmt_string(p,"status","Process Status",
+ (ps_record.process_status == SB_WORKING) ?
"working" : "idle_die");
+
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"worker_count")==0) {
+ h =
mgmt_set_mgmt_long(p,"worker_count","#Threads",ps_record.worker_threads);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"worker_count",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"thread")==0) {
+ if (ps_record.process_status == SB_WORKING) {
+ if ( level +1 >= maxLevel ||
strcmp(elements[level+1],"*")==0 ) {
+ for (i=0;i<ps_record.worker_threads;i++)
{
+ apr_hash_t *t =apr_hash_make(p);
+ h =
mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",i),"thread",t);
+
apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",i),APR_HASH_KEY_STRING,h);
+
mgmt_get_var_current_worker_thread_detail(p, "",
elements,level+2,maxLevel,t,child,i);
+ }
+ } else {
+ int thread = atoi(elements[level+1]);
+ if ( level +2 >= maxLevel ||
strcmp(elements[level+2],"*")==0 ) {
+ apr_hash_t *t =apr_hash_make(p);
+ h =
mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",thread),"thread",t);
+
apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",thread),APR_HASH_KEY_STRING,h);
+
mgmt_get_var_current_worker_thread_detail(p, "",
elements,level+2,maxLevel,t,child,thread);
+ } else
+
mgmt_get_var_current_worker_thread_detail(p,
apr_psprintf(p,"%s%s.%d.",keyPrefix,"thread",thread),
elements,level+2,maxLevel, ht,child,thread);
+ }
+ }
+ }
+ return DECLINED;
+
+}
+static int mgmt_get_var_current(apr_pool_t *p, const char*keyPrefix,
const char**elements, int level, const int maxLevel, apr_hash_t *ht )
+{
+ worker_score ws_record;
+ int i,j;
+ const unsigned int KBYTE=1024;
+ unsigned long lres=0;
+ unsigned long bytes=0;
+ unsigned long count=0;
+ unsigned long bcount=0;
+ unsigned long kbcount=0;
+ unsigned long status_count[SERVER_NUM_STATUS];
+ int bWantDetail=0;
+ int bWantSummary=0;
+ apr_hash_t *hDetail=NULL;
+ ap_mgmt_item_t *h;
+ char*keyBase;
+ const char*word;
+ if (level >= maxLevel)
+ word=NULL;
+ else {
+ if ( strcmp(elements[level],"*")==0 )
+ word = NULL;
+ else;
+ word=elements[level];
+ }
+
+ if (word == NULL || strcmp(word,"worker")==0) {
+ bWantDetail=1;
+ if ((level+1) < maxLevel &&
strcmp(elements[level+1],"*") != 0 ) {
+ int child_num;
+
+ child_num=atoi(elements[level+1]);
+
keyBase=apr_pstrcat(p,keyPrefix,".worker.",elements[level+1],".",NULL);
+ return
mgmt_get_var_current_worker_child(p,keyBase,elements,level+2,maxLevel,ht,child_num);
+ }
+
+ }
+ if (word == NULL || strcmp(word,"summary")==0) {
+ bWantSummary=1;
+ }
+
+ if (bWantSummary==0 && bWantDetail == 0 )
+ return DECLINED;
+
+ for (i=0;i<SERVER_NUM_STATUS;i++) {
+ status_count[i]=0;
+ }
+
+ for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
+ if ( bWantDetail ==1 ) {
+ apr_hash_t *t =apr_hash_make(p);
+ h =
mgmt_set_mgmt_hash(p,apr_psprintf(p,"%d",i),"child",t);
+ apr_hash_set(ht,
apr_psprintf(p,"%s.worker.%d",keyPrefix,i),APR_HASH_KEY_STRING,h);
+
mgmt_get_var_current_worker_child(p,"",elements,level+2,maxLevel,t,i);
+ }
+
+ if ( bWantSummary == 1 ) {
+ for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
+ ws_record =
ap_scoreboard_image->servers[i][j];
+ status_count[ws_record.status]++;
+ lres = ws_record.access_count;
+ bytes = ws_record.bytes_served;
+ count += lres;
+ bcount += bytes;
+ if (bcount >= KBYTE) {
+ kbcount += (bcount >> 10);
+ bcount = bcount & 0x3ff;
+ }
+ }
+ }
+ }
+
+ if (bWantSummary==1) {
+ apr_hash_t *hSub;
+ char*baseKey;
+ const char *sumWord;
+
+ if (level+1 >= maxLevel ||
strcmp(elements[level+1],"*")==0) {
+ hSub = apr_hash_make(p);
+ h =
mgmt_set_mgmt_hash(p,"summary","summary",hSub);
+ apr_hash_set(ht,
apr_pstrcat(p,keyPrefix,".summary",NULL),APR_HASH_KEY_STRING,h);
+ baseKey="";
+ sumWord=NULL;
+ }
+ else {
+ sumWord=elements[level+1];
+ hSub = ht;
+ baseKey =
apr_pstrcat(p,keyPrefix,".summary.",NULL);
+ }
+ if (sumWord == NULL || strcmp(sumWord,"kbytes")==0) {
+ h = mgmt_set_mgmt_long(p,"kbytes","KB
Served",kbcount);
+ if (baseKey)
+ apr_hash_set(hSub,
apr_pstrcat(p,baseKey,"kbytes",NULL),APR_HASH_KEY_STRING,h);
+ else
+ apr_hash_set(hSub,
"kbytes",APR_HASH_KEY_STRING,h);
+ }
+ if (sumWord == NULL || strcmp(sumWord,"request")==0) {
+ h = mgmt_set_mgmt_long(p,"request","Requests
served",count);
+ if (baseKey)
+ apr_hash_set(hSub,
apr_pstrcat(p,baseKey,"request",NULL),APR_HASH_KEY_STRING,h);
+ else
+ apr_hash_set(hSub,
"requests",APR_HASH_KEY_STRING,h);
+ }
+ if (sumWord == NULL || strcmp(sumWord,"status")==0) {
+ const char*statusKey;
+ apr_hash_t *hStatus;
+ int i,j;
+ if ( level+2>= maxLevel ||elements[ level+2] ==
"*" ) {
+ hStatus = apr_hash_make(p);
+ h =
mgmt_set_mgmt_hash(p,"status","status summary",hStatus);
+//
apr_hash_set(hSub,server_status_desc[j].key ,APR_HASH_KEY_STRING,h);
+
+
apr_hash_set(hSub,apr_pstrcat(p,baseKey,"status",NULL),APR_HASH_KEY_STRING,h);
+
+ for (i=0;i<SERVER_NUM_STATUS;i++) {
+ j=0;
+ while ( server_status_desc[j].id
!= -1 &&
+
server_status_desc[j].id != i) {
+ j++;
+ }
+ h =
mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[i]);
+
apr_hash_set(hStatus,server_status_desc[j].key ,APR_HASH_KEY_STRING,h);
+ }
+ }
+ else {
+ int j;
+ char *statusBase;
+ statusKey=elements[level+2];
+ statusBase =
apr_pstrcat(p,baseKey,"status.",NULL);
+ j=0;
+ while ( server_status_desc[j].id != -1
&&
+
strcmp(server_status_desc[j].key,statusKey)!=0) {
+ j++;
+ }
+ h =
mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[server_status_desc[j].id
]);
+
apr_hash_set(hSub,apr_pstrcat(p,statusBase,server_status_desc[j].key,NULL)
,APR_HASH_KEY_STRING,h);
+
+ }
+ }
+ }
+
+ return DECLINED;
+}
+static int mgmt_get_vars( apr_pool_t *p, const char*val, apr_hash_t
*ht)
+{
+ apr_array_header_t *elements;
+ const char*word=NULL;
+ char*line=NULL;
+ const char **a;
+ char*last=NULL;
+ int i;
+
+ int bMatchAll=0;
+
+ if (val == NULL )
+ return DECLINED;
+ line = apr_pstrdup(p,val);
+ elements = apr_array_make( p,5,sizeof(char**));
+ word = apr_strtok(line,".",&last);
+ while (word != NULL ) {
+ *(const char**)apr_array_push(elements) = word;
+ word = apr_strtok(NULL,".",&last);
+ }
+
+ a= (const char**)elements->elts ;
+ i=0;
+ if (strcmp(a[i],"scoreboard")!=0 && strcmp(a[i],"*")!=0) {
+ return DECLINED;
+
+ }
+ i++;
+ word= a[i];
+
+ if ( word && strcmp(word,"*")==0 )
+ word = NULL;
+
+
+ if (word == NULL || strcmp(word,"current")==0) {
+ mgmt_get_var_current(p,"scoreboard.current",a,
i+1,elements->nelts,ht);
+ }
+ /*
+ * Info would go here
+ */
+ return DECLINED;
+}
/*
* ToDo:
* This function should be renamed to cleanup_shared
@@ -189,6 +599,7 @@
ap_scoreboard_image->global.running_generation = running_gen;
ap_restart_time = apr_time_now();
apr_pool_cleanup_register(p, NULL, ap_cleanup_scoreboard,
apr_pool_cleanup_null);
+ ap_hook_get_mgmt_items(mgmt_get_vars, NULL,NULL,
APR_HOOK_MIDDLE);
}
/* Routines called to deal with the scoreboard image
--
Ian Holsman
Performance Measurement and Analysis
CNET Networks
PH: (415) 364 8608
Index: scoreboard.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/scoreboard.c,v
retrieving revision 1.24
diff -u -r1.24 scoreboard.c
--- scoreboard.c 2001/05/22 01:31:12 1.24
+++ scoreboard.c 2001/06/18 22:40:57
@@ -88,6 +88,416 @@
#include "apr_shmem.h"
static apr_shmem_t *scoreboard_shm = NULL;
#endif
+
+/*
+ * Sets a individual detail level for a given child/thread pair
+ *
+ */
+struct server_status_desc {
+ char id;
+ const char*key;
+ const char *description;
+};
+
+static const struct server_status_desc server_status_desc[] = {
+ {SERVER_DEAD, "dead", "Server Dead"},
+ {SERVER_STARTING, "starting", "Server Starting Up"},
+ {SERVER_READY, "waiting", "Waiting for connection"},
+ {SERVER_BUSY_READ, "reading", "Reading a client request"},
+ {SERVER_BUSY_WRITE, "writing", "Processing a client request"},
+ {SERVER_BUSY_KEEPALIVE,"keepalive", "Waiting for more requests via
+keepalive"},
+ {SERVER_BUSY_LOG, "log", "Logging the Request"},
+ {SERVER_BUSY_DNS, "dns", "Looking up a hostname"},
+ {SERVER_GRACEFUL, "gracefull","server is gracefully finishing request"},
+ {SERVER_ACCEPTING, "accepting","thread is accepting connections"},
+ {SERVER_QUEUEING, "queueing", "thread is putting connection on the
+queue"},
+ {SERVER_IDLE_KILL, "idlekill", "Server is cleaning up idle children"},
+ {-1, "unknown","unknown/invalid key"}
+};
+
+/*
+ * TODO: move helper functions out of scoreboard
+ * mgmt_set_mgmt_long -- sets a line which represents a 'long'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_long(apr_pool_t *p, const char*name, const
+char*desc,long val)
+{
+ ap_mgmt_item_t* h;
+ h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+ h->name= name;
+ h->description = desc;
+ h->vtype= ap_mgmt_type_long;
+ h->v.i_value = val;
+ return h;
+}
+/*
+ * mgmt_set_mgmt_string -- sets a line which represents a 'string'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_string(apr_pool_t *p, const char*name, const
+char*desc,const char*val)
+{
+ ap_mgmt_item_t* h;
+ h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+ h->name= name;
+ h->description = desc;
+ h->vtype= ap_mgmt_type_string;
+ h->v.s_value = val;
+ return h;
+}
+/*
+ * mgmt_set_mgmt_hash -- sets a line which represents a group of other keys
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_hash(apr_pool_t *p, const char*name, const
+char*desc,apr_hash_t *val)
+{
+ ap_mgmt_item_t* h;
+ h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+ h->name= name;
+ h->description = desc;
+ h->vtype= ap_mgmt_type_hash;
+ h->v.h_value = val;
+ return h;
+}
+
+/*
+ * get variables related to a individual thread
+ */
+static int mgmt_get_var_current_worker_thread_detail(apr_pool_t *p, const
+char*keyPrefix,
+ const char**elements, int level, const int maxLevel, apr_hash_t *ht,
+ int child_num, int thread_num )
+{
+ int bWantAll=0;
+ worker_score ws_record;
+ ap_mgmt_item_t *h;
+
+ const char*word;
+ if (level >= maxLevel)
+ word=NULL;
+ else {
+ if ( strcmp(elements[level],"*")==0 )
+ word = NULL;
+ else
+ word=elements[level];
+ }
+
+
+ if ( child_num > HARD_SERVER_LIMIT || thread_num > HARD_THREAD_LIMIT) {
+ return DECLINED;
+ }
+
+ ws_record = ap_scoreboard_image->servers[child_num][thread_num];
+
+ if ( word == NULL || strcmp(word,"thread_num")==0) {
+ h = mgmt_set_mgmt_long(p, "thread_num", "Thread
+Number",ws_record.thread_num);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"thread_num",NULL),APR_HASH_KEY_STRING,h);
+ }
+ /* XXX: ?? should be handled by MPM perhaps? or in a arch-specific call?*/
+#if APR_HAS_THREADS
+ if ( word == NULL || strcmp(word,"tid")==0) {
+ h = mgmt_set_mgmt_long(p, "tid", "Thread ID (OS
+Specific)",(long)ws_record.tid);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"tid",NULL),APR_HASH_KEY_STRING,h);
+ }
+#endif
+ if ( word == NULL || strcmp(word,"status")==0) {
+ int i=0;
+ while ( server_status_desc[i].id != -1 &&
+ server_status_desc[i].id != ws_record.status) {
+
+ i++;
+ }
+
+ if (i == -1 ) {
+ h = mgmt_set_mgmt_string(p, "status","??unknown/invalid
+status??","??unknown??");
+ } else {
+ h = mgmt_set_mgmt_string(p,
+"status",server_status_desc[i].description,server_status_desc[i].key);
+ }
+
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"access_slot")==0) {
+ h = mgmt_set_mgmt_long(p, "access_slot","Access Counts for this
+slot",ws_record.access_count);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_slot",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"access_connection")==0) {
+ h = mgmt_set_mgmt_long(p, "access_connection","Access Counts for this
+connection",ws_record.conn_count);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_connection",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"access_child")==0) {
+ h = mgmt_set_mgmt_long(p, "access_child","Access Counts for this
+child",ws_record.my_access_count);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_child",NULL),APR_HASH_KEY_STRING,h);
+ }
+
+ if ( word == NULL || strcmp(word,"bytes_slot")==0) {
+ h = mgmt_set_mgmt_long(p, "bytes_slot","bytes served for this
+slot",ws_record.bytes_served);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_slot",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"bytes_connection")==0) {
+ h = mgmt_set_mgmt_long(p, "bytes_connection","bytes served for this
+connection",ws_record.conn_bytes);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_connection",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"bytes_child")==0) {
+ h = mgmt_set_mgmt_long(p, "bytes_child","bytes served for this
+child",ws_record.my_bytes_served);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_child",NULL),APR_HASH_KEY_STRING,h);
+ }
+
+ if ( word == NULL || strcmp(word,"request")==0) {
+ h = mgmt_set_mgmt_string(p, "request","the request currently being
+processed",apr_pstrdup(p,ws_record.request));
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"request",NULL),APR_HASH_KEY_STRING,h);
+ }
+
+ return OK;
+}
+static int mgmt_get_var_current_worker_child(apr_pool_t *p, const char*keyPrefix,
+const char**elements, int level, const int maxLevel, apr_hash_t *ht, int child )
+{
+ int i;
+ process_score ps_record;
+ const char*word;
+ ap_mgmt_item_t *h;
+
+ if ( child > HARD_SERVER_LIMIT )
+ return DECLINED;
+ ps_record = ap_scoreboard_image->parent[child];
+
+
+
+ if (level >= maxLevel)
+ word=NULL;
+ else {
+ if ( strcmp(elements[level],"*")==0 )
+ word = NULL;
+ else
+ word=elements[level];
+ }
+
+ if ( word == NULL || strcmp(word,"pid")==0) {
+ h = mgmt_set_mgmt_long(p,"pid","Process ID",ps_record.pid);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"pid",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"generation")==0) {
+ h = mgmt_set_mgmt_long(p,"generation","Process
+Generation",ps_record.generation);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"generation",NULL),APR_HASH_KEY_STRING,h);
+
+ }
+ if ( word == NULL || strcmp(word,"type")==0) {
+ h = mgmt_set_mgmt_string(p,"scoreboardType","Scoreboard Type",
+ (ps_record.sb_type == SB_SHARED)? "shared":"not
+shared");
+
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"type",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"status")==0) {
+ h = mgmt_set_mgmt_string(p,"status","Process Status",
+ (ps_record.process_status == SB_WORKING) ? "working" :
+"idle_die");
+
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);
+ }
+ if ( word == NULL || strcmp(word,"worker_count")==0) {
+ h =
+mgmt_set_mgmt_long(p,"worker_count","#Threads",ps_record.worker_threads);
+
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"worker_count",NULL),APR_HASH_KEY_STRING,h);
+
+ }
+ if ( word == NULL || strcmp(word,"thread")==0) {
+ if (ps_record.process_status == SB_WORKING) {
+ if ( level +1 >= maxLevel || strcmp(elements[level+1],"*")==0
+) {
+ for (i=0;i<ps_record.worker_threads;i++) {
+ apr_hash_t *t =apr_hash_make(p);
+ h =
+mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",i),"thread",t);
+
+apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",i),APR_HASH_KEY_STRING,h);
+
+ mgmt_get_var_current_worker_thread_detail(p,
+"", elements,level+2,maxLevel,t,child,i);
+ }
+ } else {
+ int thread = atoi(elements[level+1]);
+ if ( level +2 >= maxLevel ||
+strcmp(elements[level+2],"*")==0 ) {
+ apr_hash_t *t =apr_hash_make(p);
+ h =
+mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",thread),"thread",t);
+
+apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",thread),APR_HASH_KEY_STRING,h);
+
+ mgmt_get_var_current_worker_thread_detail(p,
+"", elements,level+2,maxLevel,t,child,thread);
+ } else
+ mgmt_get_var_current_worker_thread_detail(p,
+apr_psprintf(p,"%s%s.%d.",keyPrefix,"thread",thread), elements,level+2,maxLevel,
+ht,child,thread);
+ }
+ }
+ }
+ return DECLINED;
+
+}
+static int mgmt_get_var_current(apr_pool_t *p, const char*keyPrefix, const
+char**elements, int level, const int maxLevel, apr_hash_t *ht )
+{
+ worker_score ws_record;
+ int i,j;
+ const unsigned int KBYTE=1024;
+ unsigned long lres=0;
+ unsigned long bytes=0;
+ unsigned long count=0;
+ unsigned long bcount=0;
+ unsigned long kbcount=0;
+ unsigned long status_count[SERVER_NUM_STATUS];
+ int bWantDetail=0;
+ int bWantSummary=0;
+ apr_hash_t *hDetail=NULL;
+ ap_mgmt_item_t *h;
+ char*keyBase;
+ const char*word;
+ if (level >= maxLevel)
+ word=NULL;
+ else {
+ if ( strcmp(elements[level],"*")==0 )
+ word = NULL;
+ else;
+ word=elements[level];
+ }
+
+ if (word == NULL || strcmp(word,"worker")==0) {
+ bWantDetail=1;
+ if ((level+1) < maxLevel && strcmp(elements[level+1],"*") != 0 ) {
+ int child_num;
+
+ child_num=atoi(elements[level+1]);
+
+
+keyBase=apr_pstrcat(p,keyPrefix,".worker.",elements[level+1],".",NULL);
+ return
+mgmt_get_var_current_worker_child(p,keyBase,elements,level+2,maxLevel,ht,child_num);
+ }
+
+ }
+ if (word == NULL || strcmp(word,"summary")==0) {
+ bWantSummary=1;
+ }
+
+ if (bWantSummary==0 && bWantDetail == 0 )
+ return DECLINED;
+
+ for (i=0;i<SERVER_NUM_STATUS;i++) {
+ status_count[i]=0;
+ }
+
+ for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
+ if ( bWantDetail ==1 ) {
+ apr_hash_t *t =apr_hash_make(p);
+ h = mgmt_set_mgmt_hash(p,apr_psprintf(p,"%d",i),"child",t);
+
+ apr_hash_set(ht,
+apr_psprintf(p,"%s.worker.%d",keyPrefix,i),APR_HASH_KEY_STRING,h);
+
+mgmt_get_var_current_worker_child(p,"",elements,level+2,maxLevel,t,i);
+ }
+
+ if ( bWantSummary == 1 ) {
+ for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
+ ws_record = ap_scoreboard_image->servers[i][j];
+ status_count[ws_record.status]++;
+ lres = ws_record.access_count;
+ bytes = ws_record.bytes_served;
+ count += lres;
+ bcount += bytes;
+ if (bcount >= KBYTE) {
+ kbcount += (bcount >> 10);
+ bcount = bcount & 0x3ff;
+ }
+ }
+ }
+ }
+
+ if (bWantSummary==1) {
+ apr_hash_t *hSub;
+ char*baseKey;
+ const char *sumWord;
+
+ if (level+1 >= maxLevel || strcmp(elements[level+1],"*")==0) {
+ hSub = apr_hash_make(p);
+ h = mgmt_set_mgmt_hash(p,"summary","summary",hSub);
+ apr_hash_set(ht,
+apr_pstrcat(p,keyPrefix,".summary",NULL),APR_HASH_KEY_STRING,h);
+ baseKey="";
+ sumWord=NULL;
+ }
+ else {
+ sumWord=elements[level+1];
+ hSub = ht;
+ baseKey = apr_pstrcat(p,keyPrefix,".summary.",NULL);
+ }
+ if (sumWord == NULL || strcmp(sumWord,"kbytes")==0) {
+ h = mgmt_set_mgmt_long(p,"kbytes","KB Served",kbcount);
+ if (baseKey)
+ apr_hash_set(hSub,
+apr_pstrcat(p,baseKey,"kbytes",NULL),APR_HASH_KEY_STRING,h);
+ else
+ apr_hash_set(hSub, "kbytes",APR_HASH_KEY_STRING,h);
+ }
+ if (sumWord == NULL || strcmp(sumWord,"request")==0) {
+ h = mgmt_set_mgmt_long(p,"request","Requests served",count);
+ if (baseKey)
+ apr_hash_set(hSub,
+apr_pstrcat(p,baseKey,"request",NULL),APR_HASH_KEY_STRING,h);
+ else
+ apr_hash_set(hSub, "requests",APR_HASH_KEY_STRING,h);
+ }
+ if (sumWord == NULL || strcmp(sumWord,"status")==0) {
+ const char*statusKey;
+ apr_hash_t *hStatus;
+ int i,j;
+ if ( level+2>= maxLevel ||elements[ level+2] == "*" ) {
+ hStatus = apr_hash_make(p);
+ h = mgmt_set_mgmt_hash(p,"status","status
+summary",hStatus);
+// apr_hash_set(hSub,server_status_desc[j].key
+,APR_HASH_KEY_STRING,h);
+
+
+apr_hash_set(hSub,apr_pstrcat(p,baseKey,"status",NULL),APR_HASH_KEY_STRING,h);
+
+ for (i=0;i<SERVER_NUM_STATUS;i++) {
+ j=0;
+ while ( server_status_desc[j].id != -1 &&
+ server_status_desc[j].id != i)
+{
+ j++;
+ }
+ h =
+mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[i]);
+ apr_hash_set(hStatus,server_status_desc[j].key
+,APR_HASH_KEY_STRING,h);
+ }
+ }
+ else {
+ int j;
+ char *statusBase;
+ statusKey=elements[level+2];
+ statusBase = apr_pstrcat(p,baseKey,"status.",NULL);
+ j=0;
+ while ( server_status_desc[j].id != -1 &&
+
+strcmp(server_status_desc[j].key,statusKey)!=0) {
+ j++;
+ }
+ h =
+mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[server_status_desc[j].id
+ ]);
+
+apr_hash_set(hSub,apr_pstrcat(p,statusBase,server_status_desc[j].key,NULL)
+,APR_HASH_KEY_STRING,h);
+
+ }
+ }
+ }
+
+ return DECLINED;
+}
+static int mgmt_get_vars( apr_pool_t *p, const char*val, apr_hash_t *ht)
+{
+ apr_array_header_t *elements;
+ const char*word=NULL;
+ char*line=NULL;
+ const char **a;
+ char*last=NULL;
+ int i;
+
+ int bMatchAll=0;
+
+ if (val == NULL )
+ return DECLINED;
+ line = apr_pstrdup(p,val);
+ elements = apr_array_make( p,5,sizeof(char**));
+ word = apr_strtok(line,".",&last);
+ while (word != NULL ) {
+ *(const char**)apr_array_push(elements) = word;
+ word = apr_strtok(NULL,".",&last);
+ }
+
+ a= (const char**)elements->elts ;
+ i=0;
+ if (strcmp(a[i],"scoreboard")!=0 && strcmp(a[i],"*")!=0) {
+ return DECLINED;
+
+ }
+ i++;
+ word= a[i];
+
+ if ( word && strcmp(word,"*")==0 )
+ word = NULL;
+
+
+ if (word == NULL || strcmp(word,"current")==0) {
+ mgmt_get_var_current(p,"scoreboard.current",a, i+1,elements->nelts,ht);
+ }
+ /*
+ * Info would go here
+ */
+ return DECLINED;
+}
/*
* ToDo:
* This function should be renamed to cleanup_shared
@@ -189,6 +599,7 @@
ap_scoreboard_image->global.running_generation = running_gen;
ap_restart_time = apr_time_now();
apr_pool_cleanup_register(p, NULL, ap_cleanup_scoreboard, apr_pool_cleanup_null);
+ ap_hook_get_mgmt_items(mgmt_get_vars, NULL,NULL, APR_HOOK_MIDDLE);
}
/* Routines called to deal with the scoreboard image
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_main.h"
#include "util_script.h"
#include <time.h>
#include "http_log.h"
#define CORE_PRIVATE
#include "apr.h"
#include "apr_strings.h"
#include "apr_hooks.h"
#include "apr_hash.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
/* mod_mgmt.c - by Ian Holsman <[EMAIL PROTECTED]>
*
* Basic Management module
*/
AP_MODULE_DECLARE_DATA module mgmt_module;
typedef struct {
int level;
} mgmt_config;
/* simple little function to write an APR error string and exit */
static void apr_err(const char *s, apr_status_t rv)
{
char buf[120];
fprintf(stderr,
"%s: %s (%d)\n",
s, apr_strerror(rv, buf, sizeof buf), rv);
exit(rv);
}
/*
* Create a configuration specific to this module for a server or directory
* location, and fill it with the default settings.
*
* The API says that in the absence of a merge function, the record for the
* closest ancestor is used exclusively. That's what we want, so we don't
* bother to have such a function.
*/
static void *mkconfig(apr_pool_t *p)
{
mgmt_config *cfg = apr_pcalloc(p, sizeof(mgmt_config));
cfg->level = 0;
return cfg;
}
/*
* Respond to a callback to create configuration record for a server or
* vhost environment.
*/
static void *create_mconfig_for_server(apr_pool_t *p, server_rec *s)
{
return mkconfig(p);
}
/*
* Respond to a callback to create a config record for a specific directory.
*/
static void *create_mconfig_for_directory(apr_pool_t *p, char *dir)
{
return mkconfig(p);
}
static void mgmt_dump_hash_xml(request_rec *r, apr_hash_t *ht, int level)
{
apr_hash_index_t *iterator;
iterator = apr_hash_first(ht);
while (iterator) {
ap_mgmt_item_t *line;
char*key;
apr_hash_this(iterator,&key,NULL,&line);
ap_rprintf(r,"<%s><name>%s</name><desc>%s</desc>\n", key, line->name, line->description );
if ( line->vtype== ap_mgmt_type_long ) {
ap_rprintf(r," <long>%ld</long>\n", line->v.i_value);
} else if (line->vtype == ap_mgmt_type_string) {
ap_rputs(" <string>", r);
ap_rputs(line->v.s_value , r);
ap_rputs("</string>\n", r);
} else if ( line->vtype == ap_mgmt_type_hash) {
mgmt_dump_hash_xml(r, line->v.h_value, level+1);
} else {
ap_rprintf(r,"<unknown>%ld</unknown>\n",line->vtype );
}
ap_rprintf(r,"</%s>\n",key);
iterator = apr_hash_next(iterator);
}
}
static void mgmt_dump_hash_html(request_rec *r, apr_hash_t *ht, int level)
{
apr_hash_index_t *iterator;
iterator = apr_hash_first(ht);
while (iterator) {
ap_mgmt_item_t *line;
char*key;
apr_hash_this(iterator,&key,NULL,&line);
ap_rprintf(r,"Level: %d Key: <i>%s</i> Name: %s Desc: %s ", level, key, line->name , line->description );
if ( line->vtype== ap_mgmt_type_long ) {
ap_rprintf(r," <strong>%ld</strong>", line->v.i_value);
} else if (line->vtype == ap_mgmt_type_string) {
ap_rputs(" <strong>", r);
ap_rputs(line->v.s_value , r);
ap_rputs("</strong>", r);
} else if ( line->vtype == ap_mgmt_type_hash) {
ap_rputs("<ul>", r);
mgmt_dump_hash_html(r, line->v.h_value, level+1);
ap_rputs("</ul>", r);
} else {
ap_rprintf(r,"??unknown value type %ld??",line->vtype );
}
ap_rputs("<br>\n",r);
iterator = apr_hash_next(iterator);
}
}
static int mgmt_handler(request_rec *r)
{
apr_hash_t *ht;
int bXML=0;
if (strcmp(r->handler, "mgmt-status")!=0) {
return DECLINED;
}
r->allowed = (1 << M_GET);
if (r->method_number != M_GET)
return DECLINED;
if (ap_strstr(r->uri,"/xml") != NULL ) {
bXML=1;
}
if (bXML==1) {
r->content_type = "text/xml";
ap_rputs("<?xml version=\"1.0\" ?>\n", r);
ap_rputs("<status>\n", r);
ap_rvputs(r, "<servername>",ap_get_server_name(r), "</servername>\n", NULL);
} else {
r->content_type = "text/html";
ap_rputs(DOCTYPE_HTML_3_2
"<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</HEAD><BODY>\n", r);
ap_rputs("<H1>Apache Server Status for ", r);
ap_rvputs(r, ap_get_server_name(r), "</H1>\n\n", NULL);
}
ht = apr_hash_make(r->pool);
if (r->args) {
char*args;
char*token;
char*strtok_state;
args=apr_pstrdup(r->pool,r->args);
while ((token=apr_strtok(args,"&",&strtok_state))!= NULL) {
args=NULL;
ap_run_get_mgmt_items(r->pool,token, ht );
}
}
else
ap_run_get_mgmt_items(r->pool,"*", ht );
if (bXML==1) {
mgmt_dump_hash_xml(r, ht,0);
ap_rputs("</status>\n", r);
} else {
mgmt_dump_hash_html(r, ht,0);
ap_rputs("</BODY></HTML>", r);
}
return OK;
}
static const char *set_mgmt(cmd_parms *cmd, void *mconfig, const char *name)
{
mgmt_config *dcfg = (mgmt_config *) mconfig;
dcfg->level = atoi(name);
return NULL;
}
/*
* Define the directives specific to this module. This structure is referenced
* later by the 'module' structure.
*/
static const command_rec mgmt_cmds[] =
{
AP_INIT_TAKE1("mgmt", set_mgmt, NULL, RSRC_CONF, "Default Level for Walks"),
{ NULL }
};
static int mgmt_get_vars( apr_pool_t *p, const char*val, apr_hash_t *ht) {
ap_mgmt_item_t *h;
char *key;
int bMatchAll =0;
int bMatchModule=0;
int bMatched=0;
if ( strcmp(val,"*") ==0 || strcmp(val,"test.*")==0) {
bMatchModule=1;
if ( val[0]=='*')
bMatchAll=1;
}
if (bMatchModule == 1 || strcmp(val, "test.123")==0){
bMatched=1;
key = "test.123";
h = apr_palloc(p, sizeof (ap_mgmt_item_t));
h->description = "Dummy line 1";
h->name = "mod_mgmt test123";
h->vtype= ap_mgmt_type_string;
h->v.s_value = "This is a dummy string value";
apr_hash_set(ht, key,strlen(key),(void*)h);
}
if (bMatchModule == 1 || strcmp(val, "test.234")==0) {
bMatched=1;
key = "test.234";
h = apr_palloc(p, sizeof (ap_mgmt_item_t));
h->description = "Dummy line 2";
h->name= "mod_mgmt";
h->vtype = ap_mgmt_type_long;
h->v.i_value = 34L;
apr_hash_set(ht, key,strlen(key),(void*)h);
}
if (bMatchModule == 1 || strncmp("test.456",val,strlen( "test.456"))==0) {
apr_hash_t *subHash;
ap_mgmt_item_t *subLine;
int bSubMatchAll=0;
bMatched=1;
if (strcmp("test.456.*",val)==0) {
bSubMatchAll=1;
}
if (strcmp("test.456",val)==0 || bMatchModule ==1 || bSubMatchAll==1) {
key = "test.456";
h = apr_palloc(p, sizeof (ap_mgmt_item_t));
h->description = "Dummy line 3 (summary)";
h->name ="mod_mgmt";
if (bSubMatchAll == 0 || bMatchModule ==1) {
h->vtype = ap_mgmt_type_string;
h->v.s_value=apr_pstrdup(p,"Summary of line 3");
} else {
h->vtype = ap_mgmt_type_hash;
subHash = apr_hash_make(p);
subLine =apr_palloc(p,sizeof( ap_mgmt_item_t));
subLine->description =apr_pstrdup(p,"sub line 1" );
subLine->name=NULL;
subLine->vtype = ap_mgmt_type_string;
subLine->v.s_value =apr_pstrdup(p,"subLine Value 1");
apr_hash_set(subHash, "subkey1",strlen("subkey1"),(void*)subLine);
subLine =apr_palloc(p,sizeof( ap_mgmt_item_t));
subLine->description =apr_pstrdup(p,"sub line 2" );
subLine->name=NULL;
subLine->vtype = ap_mgmt_type_string;
subLine->v.s_value=apr_pstrdup(p,"subLine Value 2");
apr_hash_set(subHash, "subkey2",strlen("subkey2"),(void*)subLine);
h->v.h_value = subHash;
}
}
else if (strcmp("test.456.subkey1",val)==0) {
key = apr_pstrdup(p,val);
h = apr_palloc(p, sizeof (ap_mgmt_item_t));
h->description = apr_pstrdup(p, "Dummy line 3 subkey1");
h->name = "mod_mgmt";
h->vtype = ap_mgmt_type_string;
h->v.s_value =apr_pstrdup(p,"subLine Value 1");
} else if (strcmp("test.456.subkey2",val)==0){
key = apr_pstrdup(p,val);
h = apr_palloc(p, sizeof (ap_mgmt_item_t));
h->description = "Dummy line 3 subkey2";
h->name= "mod_mgmt";
h->vtype = ap_mgmt_type_string;
h->v.s_value = "subLine Value 2";
} else {
bMatched=0;
return DECLINED;
}
apr_hash_set(ht, key,strlen(key),(void*)h);
}
if (bMatchAll ==1 )
return DECLINED;
if ( bMatched == 1)
return OK;
return DECLINED;
}
static void register_hooks(apr_pool_t *p)
{
ap_hook_handler(mgmt_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_get_mgmt_items(mgmt_get_vars, NULL,NULL, APR_HOOK_MIDDLE);
}
module AP_MODULE_DECLARE_DATA mgmt_module =
{
STANDARD20_MODULE_STUFF,
create_mconfig_for_directory, /* create per-dir config */
NULL, /* merge per-dir config */
create_mconfig_for_server, /* server config */
NULL, /* merge server config */
mgmt_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};