]> sourceware.org Git - systemtap.git/commitdiff
The logger PMDA supports multiple clients and multiple logfiles.
authorDavid Smith <dsmith@redhat.com>
Mon, 28 Mar 2011 21:04:46 +0000 (16:04 -0500)
committerDavid Smith <dsmith@redhat.com>
Mon, 28 Mar 2011 21:06:50 +0000 (16:06 -0500)
* pcp/src/pmdas/logger/logger.c: Changed to support dynamic metrics for
  logfile data, which enables multiple client/multiple logfile support.
* pcp/src/pmdas/logger/event.c: Changes to support multiple clients and
  multiple logfiles.  Abstracted the interface a bit.
* pcp/src/pmdas/logger/event.h: Moved 'struct LogfileData' definition here
  from logger.c.  Removed event_cleanup() declaration.
* pcp/src/pmdas/logger/help: Updated.
* pcp/src/pmdas/logger/pmns: Make 'perfile' the start of the dynamic
  metrics.
* pcp/src/pmdas/logger/GNUmakefile.in: Make logger.o depend on domain.h.

pcp/src/pmdas/logger/GNUmakefile.in
pcp/src/pmdas/logger/event.c
pcp/src/pmdas/logger/event.h
pcp/src/pmdas/logger/help
pcp/src/pmdas/logger/logger.c
pcp/src/pmdas/logger/pmns

index 7a4b0aad9f519bb164201a65e9373aa8e5fd03f3..7e192eb6493c0f26d56ec6a251506344f145acf1 100644 (file)
@@ -44,6 +44,7 @@ LDIRT = domain.h *.o $(IAM).log pmda$(IAM) pmda_$(IAM).so
 
 default_pcp default:   domain.h $(TARGETS)
 
+logger.o: domain.h
 logger.o percontext.o event.o: percontext.h
 event.o logger.o: event.h
 
index a32df8321af9f136e8379ff75383f6997fa4c093..13fd430f7b1f105e21e01c0628dc5076b2ce9919 100644 (file)
@@ -38,17 +38,27 @@ struct event {
     char buffer[BUF_SIZE];
 };
 
-static TAILQ_HEAD(tailhead, event) head;
-static int eventarray;
+TAILQ_HEAD(tailhead, event);
 
-/* This has to match the values in the metric table. */
-static pmID pmid_string = PMDA_PMID(0,1); /* event.param_string */
+struct EventFileData {
+    struct LogfileData *logfile;
+    int                        fd;
+    int                        numclients;
+    struct tailhead    head;
+    
+    /* current client list - allocated? */
+};
+static struct EventFileData *file_data_tab = NULL;
+
+static int eventarray;
+static int numlogfiles;
 
 struct ctx_client_data {
-    struct event **last;              /* addr of last next element */
+    unsigned int       active_logfile;
+    struct event      **last;
 };
 
-static int monitorfd = 0;
+static void event_cleanup(void);
 
 static void *
 ctx_start_callback(int ctx)
@@ -56,13 +66,11 @@ ctx_start_callback(int ctx)
     struct ctx_client_data *c = ctx_get_user_data();
 
     if (c == NULL) {
-       c = malloc(sizeof(struct ctx_client_data));
+       c = calloc(numlogfiles, sizeof(struct ctx_client_data));
        if (c == NULL) {
            __pmNotifyErr(LOG_ERR, "allocation failure");
            return NULL;
        }
-       c->last = head.tqh_last;
-       __pmNotifyErr(LOG_INFO, "Setting last.");
     }
     return c;
 }
@@ -79,42 +87,60 @@ ctx_end_callback(int ctx, void *user_data)
 }
 
 void
-event_init(pmdaInterface *dispatch, const char *monitor_path)
+event_init(pmdaInterface *dispatch, struct LogfileData *logfiles,
+          int nlogfiles)
 {
-    /* initialize queue */
-    TAILQ_INIT(&head);
-    eventarray = pmdaEventNewArray();
+    int i;
 
-    /*
-     * fix the domain field in the event parameter PMIDs ...
-     * note these PMIDs must match the corresponding metrics in
-     * desctab[] and this cannot easily be done automatically
-     */
-    ((__pmID_int *)&pmid_string)->domain = dispatch->domain;
+    numlogfiles = nlogfiles;
+    if (numlogfiles <= 0 || logfiles == NULL) {
+       __pmNotifyErr(LOG_ERR, "no logfiles");
+       exit(1);
+    }
+
+    eventarray = pmdaEventNewArray();
 
     ctx_register_callbacks(ctx_start_callback, ctx_end_callback);
 
-    /* We can't really select on the logfile.  Why?  If the logfile is
-     * a normal file, select will (continually) return EOF after we've
-     * read all the data.  Then we tried a custom main that that read
-     * data before handling any message we get on the control channel.
-     * That didn't work either, since the client context wasn't set up
-     * yet (since that is the 1st control message).  So, now we read
-     * data inside the event fetch routine. */
-
-    /* Try to open logfile to monitor */
-    monitorfd = open(monitor_path, O_RDONLY|O_NONBLOCK);
-    if (monitorfd < 0) {
-       __pmNotifyErr(LOG_ERR, "open failure on %s", monitor_path);
-       exit(1);
+    /* Allocate our EventFileData table. */
+    file_data_tab = malloc(sizeof(struct EventFileData) * numlogfiles);
+    if (file_data_tab == NULL) {
+       fprintf(stderr, "%s: allocation error: %s\n", __FUNCTION__,
+               strerror(errno));
+       return;
+    }
+
+    /* Fill it the table. */
+    for (i = 0; i < numlogfiles; i++) {
+       file_data_tab[i].logfile = &logfiles[i];
+       file_data_tab[i].numclients = 0;
+       TAILQ_INIT(&file_data_tab[i].head); /* initialize queue */
     }
 
-    /* Skip to the end. */
-    //(void)lseek(monitorfd, 0, SEEK_END);
+    /* We can't really use select() on the logfiles.  Why?  If the
+     * logfile is a normal file, select will (continually) return EOF
+     * after we've read all the data.  Then we tried a custom main
+     * that that read data before handling any message we get on the
+     * control channel.  That didn't work either, since the client
+     * context wasn't set up yet (since that is the 1st control
+     * message).  So, now we read data inside the event fetch
+     * routine. */
+
+    /* Try to open all the logfiles to monitor */
+    for (i = 0; i < numlogfiles; i++) {
+       file_data_tab[i].fd = open(logfiles[i].pathname, O_RDONLY|O_NONBLOCK);
+       if (file_data_tab[i].fd < 0) {
+           __pmNotifyErr(LOG_ERR, "open failure on %s", logfiles[i].pathname);
+           exit(1);
+       }
+
+       /* Skip to the end. */
+       //(void)lseek(file_data_tab[i].fd, 0, SEEK_END);
+    }
 }
 
 static int
-event_create(int fd)
+event_create(int logfile)
 {
     ssize_t c;
 
@@ -126,8 +152,11 @@ event_create(int fd)
     }
 
     /* Read up to BUF_SIZE bytes at a time. */
-    if ((c = read(fd, e->buffer, sizeof(e->buffer) - 1)) < 0) {
-       __pmNotifyErr(LOG_ERR, "read failure: %s", strerror(errno));
+    if ((c = read(file_data_tab[logfile].fd, e->buffer,
+                 sizeof(e->buffer) - 1)) < 0) {
+       __pmNotifyErr(LOG_ERR, "read failure on %s: %s",
+                     file_data_tab[logfile].logfile->pathname,
+                     strerror(errno));
        free(e);
        return -1;
     }
@@ -137,15 +166,21 @@ event_create(int fd)
     }
 
     /* Store event in queue. */
-    e->clients = ctx_get_num();
+    e->clients = file_data_tab[logfile].numclients;
     e->buffer[c] = '\0';
-    TAILQ_INSERT_TAIL(&head, e, events);
+    TAILQ_INSERT_TAIL(&file_data_tab[logfile].head, e, events);
     __pmNotifyErr(LOG_INFO, "Inserted item, clients = %d.", e->clients);
     return 0;
 }
 
 int
-event_fetch(pmValueBlock **vbpp)
+event_get_clients_per_logfile(unsigned int logfile)
+{
+    return file_data_tab[logfile].numclients;
+}
+
+int
+event_fetch(pmValueBlock **vbpp, unsigned int logfile)
 {
     struct event *e, *next;
     struct timeval stamp;
@@ -154,8 +189,16 @@ event_fetch(pmValueBlock **vbpp)
     int records = 0;
     struct ctx_client_data *c = ctx_get_user_data();
     
+    /* Make sure the we keep track of which clients are interested in
+     * which logfiles is up to date. */
+    if (c[logfile].active_logfile == 0) {
+       c[logfile].active_logfile = 1;
+       c[logfile].last = file_data_tab[logfile].head.tqh_last;
+       file_data_tab[logfile].numclients++;
+    }
+
     /* Update the event queue with new data (if any). */
-    if ((rc = event_create(monitorfd)) < 0)
+    if ((rc = event_create(logfile)) < 0)
        return rc;
 
     if (vbpp == NULL)
@@ -167,14 +210,16 @@ event_fetch(pmValueBlock **vbpp)
     if ((rc = pmdaEventAddRecord(eventarray, &stamp, PM_EVENT_FLAG_POINT)) < 0)
        return rc;
 
-    e = *c->last;
+    e = *c[logfile].last;
     while (e != NULL) {
        /* Add the string parameter.  Note that pmdaEventAddParam()
         * copies the string, so we can free it soon after. */
        atom.cp = e->buffer;
        __pmNotifyErr(LOG_INFO, "Adding param: %s", e->buffer);
-       if ((rc = pmdaEventAddParam(eventarray, pmid_string, PM_TYPE_STRING,
-                                   &atom)) < 0)
+       rc = pmdaEventAddParam(eventarray,
+                              file_data_tab[logfile].logfile->pmid_string,
+                              PM_TYPE_STRING, &atom);
+       if (rc < 0)
            return rc;
        records++;
 
@@ -183,7 +228,7 @@ event_fetch(pmValueBlock **vbpp)
 
        /* Remove the current one (if its use count is at 0). */
        if (--e->clients <= 0) {
-           TAILQ_REMOVE(&head, e, events);
+           TAILQ_REMOVE(&file_data_tab[logfile].head, e, events);
            free(e);
        }
 
@@ -192,7 +237,7 @@ event_fetch(pmValueBlock **vbpp)
     }
 
     /* Update queue pointer. */
-    c->last = head.tqh_last;
+    c[logfile].last = file_data_tab[logfile].head.tqh_last;
 
     if (records > 0)
        *vbpp = (pmValueBlock *)pmdaEventGetAddr(eventarray);
@@ -201,25 +246,32 @@ event_fetch(pmValueBlock **vbpp)
     return 0;
 }
 
-void
+static void
 event_cleanup(void)
 {
     struct event *e, *next;
     struct ctx_client_data *c = ctx_get_user_data();
+    int logfile;
 
     /* We've lost a client.  Cleanup. */
-    e = *c->last;
-    while (e != NULL) {
-       /* Get the next event. */
-       next = e->events.tqe_next;
-
-       /* Remove the current one (if its use count is at 0). */
-       if (--e->clients <= 0) {
-           TAILQ_REMOVE(&head, e, events);
-           free(e);
+    for (logfile = 0; logfile < numlogfiles; logfile++) {
+       if (c[logfile].active_logfile == 0)
+           continue;
+
+       file_data_tab[logfile].numclients--;
+       e = *c[logfile].last;
+       while (e != NULL) {
+           /* Get the next event. */
+           next = e->events.tqe_next;
+
+           /* Remove the current one (if its use count is at 0). */
+           if (--e->clients <= 0) {
+               TAILQ_REMOVE(&file_data_tab[logfile].head, e, events);
+               free(e);
+           }
+
+           /* Go on to the next event. */
+           e = next;
        }
-
-       /* Go on to the next event. */
-       e = next;
     }
 }
index f779dbe821c78757fafc79932e0e336f6381d584..6c825404b521a5c62eb5752a05867298b92efaf5 100644 (file)
 #ifndef _EVENT_H
 #define _EVENT_H
 
-extern void event_init(pmdaInterface *dispatch, const char *monitor_path);
-extern int event_fetch(pmValueBlock **vbpp);
-extern void event_cleanup(void);
+struct LogfileData {
+    char       pathname[MAXPATHLEN];
+    char       pmns_name[MAXPATHLEN];
+    pmID       pmid_string;
+};
+
+extern void event_init(pmdaInterface *dispatch, struct LogfileData *logfiles,
+                      int numlogfiles);
+extern int event_fetch(pmValueBlock **vbpp, unsigned int logfile);
+extern int event_get_clients_per_logfile(unsigned int logfile);
 
 #endif /* _EVENT_H */
index 16dd133df76d6a2bf462501db88e94cca340633d..8b998600e524e8cb7083d0fbcab4efb05ca25cb6 100644 (file)
 # blank lines before the @ line are ignored
 #
 
-@ logger.clients The number of attached clients
+@ logger.numclients The number of attached clients
 The number of attached clients.
-@ logger.event.records Logfile event records
-Logfile event records.
-@ logger.event.param_string String event data
+@ logger.numlogfiles The number of monitored logfiles
+The number of monitored logfiles.
+@ logger.param_string String event data
 String event data.
+#@ logger.perfile.numclients The number of attached clients/logfile
+#The number of attached clients/logfile
+#@ logger.perfile.records Event records/logfile
+#Event records/logfile.
index 2c706adaa529e42e9531521af990b900a15a9641..e7e3aeef36da664c4d52b2db29618de7910385f8 100644 (file)
@@ -23,6 +23,7 @@
 #include <pcp/impl.h>
 #include <pcp/pmda.h>
 #include <ctype.h>
+#include <string.h>
 #include "domain.h"
 #include "percontext.h"
 #include "event.h"
  * and could be extended to implement a much more complex PMDA.
  *
  * Metrics
- *     logger.clients          - number of attached clients
+ *     logger.numclients                       - number of attached clients
+ *     logger.numlogfiles                      - number of monitored logfiles
+ *     logger.param_string                     - string event data
+ *     logger.perfile.{LOGFILE}.numclients     - number of attached
+ *                                               clients/logfile
+ *     logger.perfile.{LOGFILE}.records        - event records/logfile
  */
 
-struct LogfileData {
-    char pathname[MAXPATHLEN];
-    int  numclients;
-    /* current client list - allocated? */
-    /* char       *pathname;  - stored in pmdaInstid */
-    /* int             fd; */
-    /* head of event queue */
-    /* perhaps a 'void *' for event.c to store stuff in? */
-};
-
 static struct LogfileData *logfiles = NULL;
 static int numlogfiles = 0;
+static int nummetrics = 0;
+static __pmnsTree *pmns;
+
+struct dynamic_metric_info {
+    int logfile;
+    int pmid_index;
+};
+static struct dynamic_metric_info *dynamic_metric_infotab = NULL;
 
 /*
  * all metrics supported in this PMDA - one table entry for each
  */
 
-static pmdaMetric metrictab[] = {
+static pmdaMetric dynamic_metrictab[] = {
+/* perfile.{LOGFILE}.numclients */
+    { (void *)0,
+      { 0 /* pmid gets filled in later */, PM_TYPE_U32, PM_INDOM_NULL,
+       PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+/* perfile.{LOGFILE}.records */
+    { (void *)1,
+      { 0 /* pmid gets filled in later */, PM_TYPE_EVENT, PM_INDOM_NULL,
+       PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, },
+};
+
+static char *dynamic_nametab[] = {
+/* perfile.numclients */
+    "numclients",
+/* perfile.records */
+    "records",
+};
+
+static pmdaMetric static_metrictab[] = {
+/* numclients */
     { NULL, 
-/* clients */
-      { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, 
-        PMDA_PMUNITS(0,0,0,0,0,0) }, },
-/* event.records */
+      { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, 
+       PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+/* numlogfiles */
     { NULL,
-      { PMDA_PMID(PM_CLUSTER_EVENT,0), PM_TYPE_EVENT, PM_INDOM_NULL,
-       PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, },
-/* event.param_string */
+      { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, 
+       PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, },
+/* param_string */
     { NULL,
-      { PMDA_PMID(0,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT,
+      { PMDA_PMID(0,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT,
        PMDA_PMUNITS(0,0,0,0,0,0) }, },
 };
 
+static pmdaMetric *metrictab = NULL;
+
 static char    mypath[MAXPATHLEN];
 static int     isDSO = 1;              /* ==0 if I am a daemon */
 char          *configfile = NULL;
@@ -103,80 +127,60 @@ logger_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)
     int                status = PMDA_FETCH_STATIC;
 
     __pmNotifyErr(LOG_INFO, "%s called\n", __FUNCTION__);
-    if ((idp->cluster == 0 && (idp->item < 0 || idp->item > 1))
-       || (idp->cluster == PM_CLUSTER_EVENT && idp->item != 0)) {
+    if (idp->cluster != 0 || (idp->item < 0 || idp->item > nummetrics)) {
        __pmNotifyErr(LOG_ERR, "%s: PM_ERR_PMID (cluster = %d, item = %d)\n",
                      __FUNCTION__, idp->cluster, idp->item);
        return PM_ERR_PMID;
     }
-    else if (inst != PM_IN_NULL) {
-       __pmNotifyErr(LOG_ERR, "%s: PM_ERR_INST (inst = %d)\n",
-                     __FUNCTION__, inst);
-       return PM_ERR_INST;
-    }
 
-    if (idp->cluster == 0) {
+    if (idp->item < 3) {
        switch(idp->item) {
-         case 0:
+         case 0:                       /* logger.numclients */
            atom->ul = ctx_get_num();
            break;
-         case 1:
+         case 1:                       /* logger.numlogfiles */
+           atom->ul = numlogfiles;
+           break;
+         case 2:                       /* logger.param_string */
            status = PMDA_FETCH_NOVALUES;
            break;
          default:
            __pmNotifyErr(LOG_ERR,
-                         "%s: PM_ERR_PMID (cluster = %d, item = %d)\n",
-                         __FUNCTION__, idp->cluster, idp->item);
+                         "%s: PM_ERR_PMID (inst = %d, cluster = %d, item = %d)\n",
+                         __FUNCTION__, inst, idp->cluster, idp->item);
            return PM_ERR_PMID;
        }
     }
-    else if (idp->cluster == PM_CLUSTER_EVENT) {
-       switch(idp->item) {
-         case 0:
-           if ((rc = event_fetch(&atom->vbp)) != 0)
+    else {
+       struct dynamic_metric_info *pinfo = ((mdesc != NULL) ? mdesc->m_user
+                                            : NULL);
+       if (pinfo == NULL) {
+           __pmNotifyErr(LOG_ERR,
+                         "%s: PM_ERR_PMID - bad pinfo (item = %d)\n",
+                         __FUNCTION__, idp->item);
+           return PM_ERR_PMID;
+       }
+
+       switch(pinfo->pmid_index) {
+         case 0:            /* logger.perfile.{LOGFILE}.numclients */
+           atom->ul = event_get_clients_per_logfile(pinfo->logfile);
+           break;
+         case 1:               /* logger.perfile.{LOGFILE}.records */
+           if ((rc = event_fetch(&atom->vbp, pinfo->logfile)) != 0)
                return rc;
            if (atom->vbp == NULL)
                status = PMDA_FETCH_NOVALUES;
            break;
          default:
            __pmNotifyErr(LOG_ERR,
-                         "%s: PM_ERR_PMID (cluster = %d, item = %d)\n",
-                         __FUNCTION__, idp->cluster, idp->item);
+                         "%s: PM_ERR_PMID (item = %d)\n", __FUNCTION__,
+                         idp->item);
            return PM_ERR_PMID;
        }
     }
-
     return status;
 }
 
-/*
- * Initialise the agent (both daemon and DSO).
- */
-void 
-logger_init(pmdaInterface *dp)
-{
-    if (isDSO) {
-       int sep = __pmPathSeparator();
-       snprintf(mypath, sizeof(mypath), "%s%c" "logger" "%c" "help",
-               pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
-       pmdaDSO(dp, PMDA_INTERFACE_5, "logger DSO", mypath);
-    }
-
-    if (dp->status != 0)
-       return;
-
-    dp->version.four.profile = logger_profile;
-
-    pmdaSetFetchCallBack(dp, logger_fetchCallBack);
-    pmdaSetEndContextCallBack(dp, logger_end_contextCallBack);
-
-    pmdaInit(dp, NULL, 0, 
-            metrictab, sizeof(metrictab)/sizeof(metrictab[0]));
-
-    /* For now, only handle the 1st logfile. */
-    event_init(dp, logfiles[0].pathname);
-}
-
 static int
 read_config(const char *filename)
 {
@@ -185,7 +189,7 @@ read_config(const char *filename)
     int                        rc = 0;
     size_t             len;
     char               tmp[MAXPATHLEN];
-    char              *endptr;
+    char              *ptr;
 
     configFile = fopen(filename, "r");
     if (configFile == NULL) {
@@ -222,14 +226,14 @@ read_config(const char *filename)
        }
        tmp[len - 1] = '\0';            /* Remove the '\n'. */
 
-       /* Remove all trailing whitespace.  Set endptr to last char of
+       /* Remove all trailing whitespace.  Set ptr to last char of
         * string. */
-       endptr = tmp + strlen(tmp) - 1;
+       ptr = tmp + strlen(tmp) - 1;
        /* While trailing whitespace, move back. */
-       while (endptr >= tmp && isspace(*endptr)) {
-           --endptr;
+       while (ptr >= tmp && isspace(*ptr)) {
+           --ptr;
        }
-       *(endptr+1) = '\0';       /* Now set '\0' as terminal byte. */
+       *(ptr+1) = '\0';          /* Now set '\0' as terminal byte. */
 
        /* If the string is now empty, just ignore the line. */
        len = strlen(tmp);
@@ -247,11 +251,38 @@ read_config(const char *filename)
            break;
        }
        data = &logfiles[numlogfiles - 1];
-       data->numclients = 0;
-       strcpy(data->pathname, tmp);
+       strncpy(data->pathname, tmp, sizeof(data->pathname));
+       /* data->pmid_string gets filled in after pmdaInit() is called. */
+
+       /* Now we've got to munge the pathname and turn it into a
+        * pmns name.  For example, "/var/log/messages" would end up
+        * as "var.log.messages".  First, skip past any leading '/'
+        * chars. */
+       ptr = tmp;
+       while (*ptr == '/') {
+           ptr++;
+           if (*ptr == '\0')
+               break;
+       }
+       /* Copy the string, then replace all the '.' characters with
+        * '_', then replace all the '/' characters with '.'. */
 
-       __pmNotifyErr(LOG_INFO, "%s: saw logfile %s\n", __FUNCTION__,
-                     data->pathname);
+       /* DRS:  FIXME - Is '_' a valid char?  I also think the 1st
+        * char must be alphabetic.  See valid_pmns_name() in
+        * pmdas/linux/cgroups.c.*/
+
+       strncpy(data->pmns_name, ptr, sizeof(data->pmns_name));
+       ptr = data->pmns_name;
+       while ((ptr = strchr(ptr, '.')) != NULL) {
+           *ptr = '_';
+       }
+       ptr = data->pmns_name;
+       while ((ptr = strchr(ptr, '/')) != NULL) {
+           *ptr = '.';
+       }
+
+       __pmNotifyErr(LOG_INFO, "%s: saw logfile %s (%s)\n", __FUNCTION__,
+                     data->pathname, data->pmns_name);
     }
     if (rc != 0) {
        free(logfiles);
@@ -275,6 +306,144 @@ usage(void)
     exit(1);
 }
 
+static int
+logger_pmid(const char *name, pmID *pmid, pmdaExt *pmda)
+{
+    __pmNotifyErr(LOG_INFO, "%s: name %s\n", __FUNCTION__,
+                 (name == NULL) ? "NULL" : name);
+    return pmdaTreePMID(pmns, name, pmid);
+}
+
+static int
+logger_name(pmID pmid, char ***nameset, pmdaExt *pmda)
+{
+    __pmNotifyErr(LOG_INFO, "%s: pmid 0x%x\n", __FUNCTION__, pmid);
+    return pmdaTreeName(pmns, pmid, nameset);
+}
+
+static int
+logger_children(const char *name, int traverse, char ***kids, int **sts,
+               pmdaExt *pmda)
+{
+    __pmNotifyErr(LOG_INFO, "%s: name %s\n", __FUNCTION__,
+                 (name == NULL) ? "NULL" : name);
+    return pmdaTreeChildren(pmns, name, traverse, kids, sts);
+}
+
+/*
+ * Initialise the agent (both daemon and DSO).
+ */
+void 
+logger_init(pmdaInterface *dp)
+{
+    int i, j, rc;
+    int numstatics = sizeof(static_metrictab)/sizeof(static_metrictab[0]);
+    int numdynamics = sizeof(dynamic_metrictab)/sizeof(dynamic_metrictab[0]);
+    pmdaMetric *pmetric;
+    int pmid_num;
+    char name[MAXPATHLEN * 2];
+    struct dynamic_metric_info *pinfo;
+
+    if (isDSO) {
+       int sep = __pmPathSeparator();
+       snprintf(mypath, sizeof(mypath), "%s%c" "logger" "%c" "help",
+               pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+       pmdaDSO(dp, PMDA_INTERFACE_5, "logger DSO", mypath);
+    }
+
+    /* Read and parse config file. */
+    if (read_config(configfile) != 0) {
+       exit(1);
+    }
+    if (numlogfiles == 0) {
+       usage();
+    }
+
+    /* Create the dynamic metric info table based on the logfile
+     * table. */
+    dynamic_metric_infotab = malloc(sizeof(struct dynamic_metric_info)
+                                   * numdynamics * numlogfiles);
+    if (dynamic_metric_infotab == NULL) {
+       fprintf(stderr, "%s: allocation error: %s\n", __FUNCTION__,
+               strerror(errno));
+       return;
+    }
+    pinfo = dynamic_metric_infotab;
+    for (i = 0; i < numlogfiles; i++) {
+       for (j = 0; j < numdynamics; j++) {
+           pinfo->logfile = i;
+           pinfo->pmid_index = j;
+           pinfo++;
+       }
+    }
+
+    /* Create the metric table based on the static and dynamic metric
+     * tables. */
+    nummetrics = numstatics + (numlogfiles * numdynamics);
+    metrictab = malloc(sizeof(pmdaMetric) * nummetrics);
+    if (metrictab == NULL) {
+       free(dynamic_metric_infotab);
+       fprintf(stderr, "%s: allocation error: %s\n", __FUNCTION__,
+               strerror(errno));
+       return;
+    }
+    memcpy(metrictab, static_metrictab, sizeof(static_metrictab));
+    pmetric = &metrictab[numstatics];
+    pmid_num = numstatics;
+    pinfo = dynamic_metric_infotab;
+    for (i = 0; i < numlogfiles; i++) {
+       memcpy(pmetric, dynamic_metrictab, sizeof(dynamic_metrictab));
+       for (j = 0; j < numdynamics; j++) {
+           pmetric[j].m_desc.pmid = PMDA_PMID(0, pmid_num);
+           pmetric[j].m_user = pinfo++;
+           pmid_num++;
+       }
+       pmetric += numdynamics;
+    }
+
+    if (dp->status != 0)
+       return;
+    dp->version.four.profile = logger_profile;
+
+    /* Dynamic PMNS handling. */
+    dp->version.four.pmid = logger_pmid;
+    dp->version.four.name = logger_name;
+    dp->version.four.children = logger_children;
+    /* DRS: if we want to generate help text for the dynamic metrics,
+     * we'll have to override 'four.text'. */
+
+    pmdaSetFetchCallBack(dp, logger_fetchCallBack);
+    pmdaSetEndContextCallBack(dp, logger_end_contextCallBack);
+
+    pmdaInit(dp, NULL, 0, metrictab, nummetrics);
+
+    /* Create the dynamic PMNS tree and populate it. */
+    if ((rc = __pmNewPMNS(&pmns)) < 0) {
+       __pmNotifyErr(LOG_ERR, "%s: failed to create new pmns: %s\n",
+                       pmProgname, pmErrStr(rc));
+       pmns = NULL;
+       return;
+    }
+    pmetric = &metrictab[numstatics];
+    for (i = 0; i < numlogfiles; i++) {
+       for (j = 0; j < numdynamics; j++) {
+           snprintf(name, sizeof(name), "logger.perfile.%s.%s",
+                    logfiles[i].pmns_name, dynamic_nametab[j]);
+           __pmAddPMNSNode(pmns, pmetric[j].m_desc.pmid, name);
+       }
+       pmetric += numdynamics;
+    }
+    pmdaTreeRebuildHash(pmns, (numlogfiles * numdynamics)); /* for reverse (pmid->name) lookups */
+
+    /* Now that the metric table has been fully filled in, update
+     * each LogfileData with the proper string pmid to use. */
+    for (i = 0; i < numlogfiles; i++) {
+       logfiles[i].pmid_string = metrictab[2].m_desc.pmid;
+    }
+
+    event_init(dp, logfiles, numlogfiles);
+}
+
 /*
  * Set up the agent if running as a daemon.
  */
@@ -308,19 +477,6 @@ main(int argc, char **argv)
     configfile = argv[optind];
 
     pmdaOpenLog(&desc);
-    if (read_config(configfile) != 0) {
-       exit(1);
-    }
-
-    /* For now, only allow 1 logfile. */
-    if (numlogfiles == 0) {
-       usage();
-    }
-    if (numlogfiles > 1) {
-       __pmNotifyErr(LOG_INFO, "%s: Only handling first logfile\n",
-                     __FUNCTION__);
-    }
-
     logger_init(&desc);
     pmdaConnect(&desc);
 
index e80dcecfa3136b9296bdf06578324bc90c3d63fc..8f7babe7e45664b4e980907b8ece3099951d0e0a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Metrics for logger PMDA
  *
- * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2011 Red Hat Inc.
  * 
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  */
 
 logger {
-    clients            LOGGER:0:0
-    event
-}
-
-logger.event {
-    records            LOGGER:4095:0
-    param_string       LOGGER:0:1
+    numclients         LOGGER:0:0
+    numlogfiles                LOGGER:0:1
+    param_string       LOGGER:0:2
+    perfile            LOGGER:*:*
 }
This page took 0.048686 seconds and 5 git commands to generate.