Apologies for the slow reply, and also for this horrible top-quoting email
client (my mutt's on the fritz atm).
I discovered my mistake with apr_array_push while going through the apr
headers. There's an init function you need to call before you can use push,
and somehow I missed it in the code I was mimicing. Given the nature of apr's
dynamic array's it seems obvious that you'd need to init it, but I assumed I
was inheriting a metric_info from somewhere and that was an invalid assumption.
I'm re-pasting the working code below in case anyone might find useful a
module that counts named processes. It will count any number of space-separated
processes given as the Value parameter (eg Value = "httpd jsvc bash"). It's
still not using strtok() safely, so I'd expect it to segfault if you installed
it and configured it in gmond.conf without passing the name of at least one
process in the Value parameter.
Idly, If I wanted to clean this up and contribute it to the project, how would
I go about it? I see some repositories for python modules, and gmetric
scripts, but nothing for user-contributed modules written in C. I'll probably
be writing a few other modules including an OpenBSD PF statistics collector.
Answers to your questions:
1. I did write a spell (package) for ganglia for SMGL, but I haven't committed
it to upstream Git, because it does a bunch of me-specific stuff (like
installing my modules etc..), and other people wouldn't probably appreciate
that.
2. I don't have what I pasted to you in front of me because my mutt is borked,
but my guess would be that I gave you a copy of the code that was hard-coded to
count something other than bash (I wouldn't be surprised. Attention to detail
is obviously not my strong suit). Check to make sure it says "bash" in the call
to count_procs() and not something non-existent (like "foo").
Thanks,
-dave
######################### Code follows #########################
#include <gm_metric.h>
#include <ganglia_priv.h>
#include <apr_strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <time.h>
#include <readproc.h> // the readproc library from the linux procps project.
most systems don't have this installed by default
extern mmodule cp_module;
static apr_array_header_t *metric_info = NULL;
char *processNames;
g_val_t count_procs(char *proc_name) {
//This function counts the number of instances of the given name (like 'httpd'
for example)
int numprocs=0;
PROCTAB *proct;
proc_t *proc_info;
g_val_t returnThis;
proct = openproc(PROC_FILLARG | PROC_FILLSTAT | PROC_FILLSTATUS);
while ((proc_info = readproc(proct,NULL))) {
if(!strncmp(proc_info->cmd,proc_name,sizeof(proc_info->cmd))){
numprocs++;
}
}
closeproc(proct);
returnThis.int32 = numprocs;
return returnThis;
}
static int cp_metric_init ( apr_pool_t *p )
{
const char* str_params = cp_module.module_params;
apr_array_header_t *list_params = cp_module.module_params_list;
mmparam *params;
Ganglia_25metric *gmi;
char processDesc[1024];
int i;
//init the metric_info array
metric_info = apr_array_make(p, 1, sizeof(Ganglia_25metric));
/* Read the parameters from the gmond.conf file. */
if (list_params) {
debug_msg("[mod_countproc] Received following params list: ");
params = (mmparam*) list_params->elts;
for(i=0; i< list_params->nelts; i++) {
debug_msg("\tParam: %s = %s", params[i].name, params[i].value);
if (!strcasecmp(params[i].name, "ProcessNames")) {
processNames = params[i].value;
}
}
}
// metadata storage
char processNamesCp[sizeof(processNames)+1];
strcpy(processNamesCp, processNames ); //avoid allowing strtok to clobber
the original ProcessNames string
char * processName = strtok(processNamesCp, " ");
for(i=0; processName != NULL; i++) {
gmi = apr_array_push(metric_info);
debug_msg("\t gmi init done");
/* gmi->key will be automatically assigned by gmond */
gmi->name = apr_pstrdup (p, processName);
gmi->tmax = 512;
gmi->type = GANGLIA_VALUE_UNSIGNED_INT;
gmi->units = apr_pstrdup(p, "count");
gmi->slope = apr_pstrdup(p, "both");
gmi->fmt = apr_pstrdup(p, "%u");
gmi->msg_size = UDP_HEADER_SIZE+8;
gmi->desc = apr_pstrdup(p, "process count");
MMETRIC_INIT_METADATA(gmi,p);
MMETRIC_ADD_METADATA(gmi,MGROUP,"cprocs");
processName = strtok(NULL, " ");
}
/* Add a terminator to the array and replace the empty static metric
definition
array with the dynamic array that we just created
*/
gmi = apr_array_push(metric_info);
memset (gmi, 0, sizeof(*gmi));
cp_module.metrics_info = (Ganglia_25metric *)metric_info->elts;
return 0;
}
static void cp_metric_cleanup ( void )
{
}
static g_val_t cp_metric_handler ( int metric_index )
{
Ganglia_25metric *gmi = &(cp_module.metrics_info[metric_index]);
g_val_t val = count_procs(gmi->name);
return val;
}
mmodule cp_module =
{
STD_MMODULE_STUFF,
cp_metric_init,
cp_metric_cleanup,
NULL, /* Dynanically defined in cp_metric_init() */
cp_metric_handler,
};
----- Original Message -----
From: "Bernard Li" <[email protected]>
To: "Dave Josephsen" <[email protected]>, "Brad Nicholes" <[email protected]>
Cc: [email protected]
Sent: Wednesday, September 22, 2010 6:31:31 PM GMT -06:00 US/Canada Central
Subject: Re: [Ganglia-general] segfault in apr_array_push trying to write a new
module
Hi Dave:
On Fri, Sep 17, 2010 at 9:41 PM, Dave Josephsen <[email protected]> wrote:
> I'm using a source-based distro called SourceMage GNU Linux, which is what
> most of our productions servers are running. Various library versions follow:
>
> Ganglia-3.1.7
Did you actually create a "package" for Ganglia?
> First, since you seem to be getting procps related errors, below is a small
> test program I wrote that uses procps to output the number of bash processes
> running on your system. This was the proof of concept from which the
> count_procs function in the module was derived, and it should confirm that
> the module's procps code is functional on your system. I'd be curious to see
> if it compiles/runs for you.
I was able to compile and run it, but it returns 0 even though I have
a couple of bash processes running. Any ideas?
> Second, I wonder, did you add a 'ProcessNames' parameter to the module
> configuration in your gmond.conf? I doubt, in it's current state, that this
> module will handle a NULL processNames variable gracefully. In fact, I'd
> fully expect it to crash and/or do other weird things since I'm calling
> strtok() on the processNames variable, without checking for nulls etc. The
> module configuration in gmond.conf should look something like the following
> (sorry, I should have mentioned that in my initial mail):
>
> module {
> name = "cp_module"
> path = "modcprocs.so"
> Param ProcessNames {
> Value = "httpd"
> }
> }
I haven't modified my gmond.conf yet as I was just trying to get the
code compiled and running first.
> Finally, do you see anything obviously wrong with my use of apr_array_push?
I'm not really an expert on apr, that's why I was just trying to
reproduce your segfault and see if I can figure something out.
Perhaps Brad has some ideas since he's our resident apr guru :)
Cheers,
Bernard
------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
Ganglia-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ganglia-general