Debuginfo allows access to current logging output through telnet.
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 16 Feb 2011 12:20:50 +0000 (13:20 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 16 Feb 2011 12:20:50 +0000 (13:20 +0100)
lib/debuginfo/src/olsrd_debuginfo.c
src/common/string.c
src/common/string.h
src/olsr_logging.c
src/olsr_logging.h

index c636a13..a053664 100644 (file)
 
 struct debuginfo_cmd {
   const char *name;
+  const char *help;
   olsr_txthandler handler;
-  struct olsr_txtcommand *cmd;
+  struct olsr_txtcommand *cmd, *cmdhelp;
 };
 
 static int debuginfo_init(void);
 static int debuginfo_enable(void);
-static int debuginfo_exit(void);
-
+static int debuginfo_disable(void);
 
 static enum olsr_txtcommand_result debuginfo_msgstat(struct comport_connection *con,
     const char *cmd, const char *param);
@@ -82,6 +82,10 @@ static enum olsr_txtcommand_result debuginfo_pktstat(struct comport_connection *
     const char *cmd, const char *param);
 static enum olsr_txtcommand_result debuginfo_cookies(struct comport_connection *con,
     const char *cmd, const char *param);
+static enum olsr_txtcommand_result debuginfo_log(struct comport_connection *con,
+    const char *cmd, const char *param);
+static enum olsr_txtcommand_result olsr_debuginfo_displayhelp(struct comport_connection *con,
+    const char *cmd, const char *param);
 
 static void update_statistics_ptr(void *);
 static void olsr_msg_statistics(struct olsr_message *,
@@ -110,15 +114,20 @@ OLSR_PLUGIN6(plugin_parameters) {
   .author = PLUGIN_AUTHOR,
   .init = debuginfo_init,
   .enable = debuginfo_enable,
-  .exit = debuginfo_exit,
+  .disable = debuginfo_disable,
   .deactivate = false
 };
 
 /* command callbacks and names */
 static struct debuginfo_cmd commands[] = {
-    {"msgstat", &debuginfo_msgstat, NULL},
-    {"pktstat", &debuginfo_pktstat, NULL},
-    {"cookies", &debuginfo_cookies, NULL}
+    {"msgstat", "Displays statistics about the incoming OLSR messages\n", &debuginfo_msgstat, NULL, NULL},
+    {"pktstat", "Displays statistics about the incoming OLSR packets\n", &debuginfo_pktstat, NULL, NULL},
+    {"cookies", "Displays statistics about memory and timer cookies\n", &debuginfo_cookies, NULL, NULL},
+    {"log",     "\"log\":      continuous output of logging to this console\n"
+                "\"log show\": show configured logging option for debuginfo output\n"
+                "\"log add <severity> <source1> <source2> ...\": Add one or more sources of a defined severity for logging\n"
+                "\"log remove <severity> <source1> <source2> ...\": Remove one or more sources of a defined severity for logging\n",
+        &debuginfo_log, NULL, NULL}
 };
 
 /* variables for statistics */
@@ -134,13 +143,18 @@ static struct olsr_timer_info *statistics_timer = NULL;
 
 static union olsr_ip_addr total_ip_addr;
 
-
+/* variables for log access */
+static bool log_debuginfo_mask[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT];
+static int log_source_maxlen, log_severity_maxlen;
+static struct comport_connection *log_connection;
+static struct log_handler_entry *log_handler;
 /**
  *Constructor
  */
 static int
 debuginfo_init(void)
 {
+  int i;
   ip_acl_init(&allowed_nets);
 
   traffic_interval = 5; /* seconds */
@@ -148,6 +162,29 @@ debuginfo_init(void)
   current_slot = 0;
 
   memset(&total_ip_addr, 255, sizeof(total_ip_addr));
+
+  /* calculate maximum length of log source names */
+  log_source_maxlen = 0;
+  for (i=1; i<LOG_SOURCE_COUNT; i++) {
+    int len = strlen(LOG_SOURCE_NAMES[i]);
+
+    if (len > log_source_maxlen) {
+      log_source_maxlen = len;
+    }
+  }
+
+  /* calculate maximum length of log severity names */
+  log_severity_maxlen = 0;
+  for (i=1; i<LOG_SEVERITY_COUNT; i++) {
+    int len = strlen(LOG_SEVERITY_NAMES[i]);
+
+    if (len > log_severity_maxlen) {
+      log_severity_maxlen = len;
+    }
+  }
+
+  memcpy(log_debuginfo_mask, log_global_mask, sizeof(log_global_mask));
+  log_connection = NULL;
   return 0;
 }
 
@@ -155,12 +192,13 @@ debuginfo_init(void)
  *Destructor
  */
 static int
-debuginfo_exit(void)
+debuginfo_disable(void)
 {
   size_t i;
 
   for (i=0; i<ARRAYSIZE(commands); i++) {
     olsr_com_remove_normal_txtcommand(commands[i].cmd);
+    olsr_com_remove_help_txtcommand(commands[i].cmdhelp);
   }
   olsr_parser_remove_function(&olsr_msg_statistics);
   olsr_preprocessor_remove_function(&olsr_packet_statistics);
@@ -186,6 +224,7 @@ debuginfo_enable(void)
 
   for (i=0; i<ARRAYSIZE(commands); i++) {
     commands[i].cmd = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
+    commands[i].cmdhelp = olsr_com_add_help_txtcommand(commands[i].name, olsr_debuginfo_displayhelp);
     commands[i].cmd->acl = &allowed_nets;
   }
 
@@ -575,6 +614,128 @@ debuginfo_cookies(struct comport_connection *con,
   return CONTINUE;
 }
 
+static enum olsr_txtcommand_result
+debuginfo_update_logfilter(struct comport_connection *con,
+    const char *cmd, const char *param, const char *current, bool value) {
+  const char *next;
+  int src, sev;
+
+  for (sev = 0; sev < LOG_SEVERITY_COUNT; sev++) {
+    if ((next = str_hasnextword(current, LOG_SEVERITY_NAMES[sev])) != NULL) {
+      break;
+    }
+  }
+  if (sev == LOG_SEVERITY_COUNT) {
+    abuf_appendf(&con->out, "Error, unknown severity in command: %s %s\n", cmd, param);
+    return CONTINUE;
+  }
+
+  current = next;
+  while (current && *current) {
+    for (src = 0; src < LOG_SOURCE_COUNT; src++) {
+      if ((next = str_hasnextword(current, LOG_SOURCE_NAMES[src])) != NULL) {
+        log_debuginfo_mask[sev][src] = value;
+        break;
+      }
+    }
+    if (src == LOG_SOURCE_COUNT) {
+      abuf_appendf(&con->out, "Error, unknown source in command: %s %s\n", cmd, param);
+      return CONTINUE;
+    }
+    current = next;
+  }
+  return CONTINUE;
+}
+
+static void
+debuginfo_print_log(enum log_severity severity __attribute__ ((unused)),
+              enum log_source source __attribute__ ((unused)),
+              bool no_header __attribute__ ((unused)),
+              const char *file __attribute__ ((unused)),
+              int line __attribute__ ((unused)),
+              char *buffer,
+              int timeLength __attribute__ ((unused)),
+              int prefixLength __attribute__ ((unused)))
+{
+  abuf_puts(&log_connection->out, buffer);
+  abuf_puts(&log_connection->out, "\n");
+
+  olsr_com_activate_output(log_connection);
+}
+
+static void
+debuginfo_stop_logging(struct comport_connection *con) {
+  con->stop_handler = NULL;
+  log_connection = NULL;
+  olsr_log_removehandler(log_handler);
+}
+
+static enum olsr_txtcommand_result
+debuginfo_log(struct comport_connection *con, const char *cmd, const char *param) {
+  const char *next;
+  int src;
+
+  if (param == NULL) {
+    if (con->stop_handler) {
+      abuf_puts(&con->out, "Error, you cannot stack continous output commands\n");
+      return CONTINUE;
+    }
+    if (log_connection != NULL) {
+      abuf_puts(&con->out, "Error, debuginfo cannot handle concurrent logging\n");
+      return CONTINUE;
+    }
+
+    log_connection = con;
+    con->stop_handler = debuginfo_stop_logging;
+
+    log_handler = olsr_log_addhandler(debuginfo_print_log, &log_debuginfo_mask);
+    return CONTINOUS;
+  }
+
+  if (strcasecmp(param, "show") == 0) {
+    abuf_appendf(&con->out, "%*s %6s %6s %6s %6s\n",
+        log_source_maxlen, "",
+        LOG_SEVERITY_NAMES[SEVERITY_DEBUG],
+        LOG_SEVERITY_NAMES[SEVERITY_INFO],
+        LOG_SEVERITY_NAMES[SEVERITY_WARN],
+        LOG_SEVERITY_NAMES[SEVERITY_ERR]);
+
+    for (src=0; src<LOG_SOURCE_COUNT; src++) {
+      abuf_appendf(&con->out, "%*s %*s %*s %*s %*s\n",
+        log_source_maxlen, LOG_SOURCE_NAMES[src],
+        log_severity_maxlen, log_debuginfo_mask[SEVERITY_DEBUG][src] ? "*" : "",
+        log_severity_maxlen, log_debuginfo_mask[SEVERITY_INFO][src] ? "*" : "",
+        log_severity_maxlen, log_debuginfo_mask[SEVERITY_WARN][src] ? "*" : "",
+        log_severity_maxlen, log_debuginfo_mask[SEVERITY_ERR][src] ? "*" : "");
+    }
+    return CONTINUE;
+  }
+
+  if ((next = str_hasnextword(param, "add")) != NULL) {
+    return debuginfo_update_logfilter(con, cmd, param, next, true);
+  }
+
+  if ((next = str_hasnextword(param, "remove")) != NULL) {
+    return debuginfo_update_logfilter(con, cmd, param, next, false);
+  }
+
+  return UNKNOWN;
+}
+
+static enum olsr_txtcommand_result
+olsr_debuginfo_displayhelp(struct comport_connection *con,
+    const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused))) {
+  size_t i;
+
+  for (i=0; i<ARRAYSIZE(commands); i++) {
+    if (strcasecmp(commands[i].name, cmd) == 0) {
+      abuf_puts(&con->out, commands[i].help);
+      return CONTINUE;
+    }
+  }
+  return UNKNOWN;
+}
+
 /*
  * Local Variables:
  * mode: c
index e96d446..fc8f267 100644 (file)
@@ -82,6 +82,35 @@ strscat(char *dest, const char *src, size_t size)
   return strscpy(dest + l, src, size > l ? size - l : 0);
 }
 
+/**
+ * Check if a string starts with a certain word. The function
+ * is not case sensitive.
+ * @param buffer pointer to string
+ * @param word pointer to the word
+ * @return pointer to the string behind the word, NULL if no match
+ */
+const char *
+str_hasnextword (const char *buffer, const char *word) {
+  /* skip whitespaces first */
+  while (isblank(*buffer)) {
+    buffer++;
+  }
+
+  while (*word != 0 && *buffer != 0 && !isblank(*buffer) && tolower(*word) == tolower(*buffer)) {
+    word++;
+    buffer++;
+  }
+
+  /* complete match ? */
+  if (*word == 0) {
+    while (isblank(*buffer)) {
+      buffer++;
+    }
+    return buffer;
+  }
+  return NULL;
+}
+
 /*
  * Local Variables:
  * c-basic-offset: 2
index c73b143..7cf055f 100644 (file)
 
 #include "defs.h"
 #include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 
 char *EXPORT(strscpy) (char *dest, const char *src, size_t size);
-
 char *EXPORT(strscat) (char *dest, const char *src, size_t size);
 
+const char *EXPORT(str_hasnextword) (const char *buffer, const char *word);
+
 extern const char *EXPORT(OLSR_YES);
 extern const char *EXPORT(OLSR_NO);
 
index 17eb374..396fee0 100644 (file)
 #include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
+#include "common/list.h"
+#include "olsr.h"
 #include "olsr_cfg.h"
 #include "olsr_cfg_data.h"
 #include "olsr_logging.h"
 #include "os_system.h"
 #include "os_time.h"
 
-struct log_handler_entry {
-  void (*handler)
-    (enum log_severity, enum log_source, bool, const char *, int, char *, int, int);
-    bool(*bitmask)[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT];
-};
+#define FOR_ALL_LOGHANDLERS(handler, iterator) list_for_each_element_safe(&log_handler_list, handler, node, iterator)
 
 bool log_global_mask[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT];
 
-static struct log_handler_entry log_handler[MAX_LOG_HANDLER];
-static int log_handler_count = 0;
-
-
+static struct list_entity log_handler_list;
 static bool log_initialized = false;
 static FILE *log_fileoutput = NULL;
 
@@ -84,19 +80,16 @@ olsr_log_init(void)
 {
   char error[256];
   bool printError = false;
-  int i, j;
+
+  list_init_head(&log_handler_list);
 
   /* clear global mask */
-  for (j = 0; j < LOG_SEVERITY_COUNT; j++) {
-    for (i = 0; i < LOG_SOURCE_COUNT; i++) {
-      log_global_mask[j][i] = false;
-    }
-  }
+  memset(&log_global_mask, 0, sizeof(log_global_mask));
 
   if (olsr_cnf->log_target_file) {
     log_fileoutput = fopen(olsr_cnf->log_target_file, "a");
     if (log_fileoutput) {
-      olsr_log_addhandler(&olsr_log_file, NULL);
+      olsr_log_addhandler(&olsr_log_file, &olsr_cnf->log_event);
     } else {
       /* handle file error for logging output */
       bool otherLog = olsr_cnf->log_target_stderr || olsr_cnf->log_target_syslog;
@@ -113,10 +106,10 @@ olsr_log_init(void)
     }
   }
   if (olsr_cnf->log_target_syslog) {
-    olsr_log_addhandler(&olsr_log_syslog, NULL);
+    olsr_log_addhandler(&olsr_log_syslog, &olsr_cnf->log_event);
   }
   if (olsr_cnf->log_target_stderr) {
-    olsr_log_addhandler(&olsr_log_stderr, NULL);
+    olsr_log_addhandler(&olsr_log_stderr, &olsr_cnf->log_event);
   }
   log_initialized = true;
 
@@ -133,6 +126,14 @@ olsr_log_init(void)
 void
 olsr_log_cleanup(void)
 {
+  struct log_handler_entry *h, *iterator;
+
+  /* remove all handlers */
+  FOR_ALL_LOGHANDLERS(h, iterator) {
+    olsr_log_removehandler(h);
+  }
+
+  /* close file output if necessary */
   if (log_fileoutput) {
     fflush(log_fileoutput);
     fclose(log_fileoutput);
@@ -140,24 +141,31 @@ olsr_log_cleanup(void)
 }
 
 /**
- * Call this function to register a custom logevent handler
+ * Registers a custom logevent handler
  * @param handler pointer to handler function
  * @param mask pointer to custom event filter or NULL if handler use filter
  *   from olsr_cnf
  */
-void
+struct log_handler_entry *
 olsr_log_addhandler(void (*handler) (enum log_severity, enum log_source, bool,
                                      const char *, int, char *, int, int),
                     bool(*mask)[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT])
 {
-
-  assert(log_handler_count < MAX_LOG_HANDLER);
-
-  log_handler[log_handler_count].handler = handler;
-  log_handler[log_handler_count].bitmask = mask;
-  log_handler_count++;
-
+  struct log_handler_entry *h;
+
+  /*
+   * The logging system is used in the memory cookie manager, so the logging
+   * system has to allocate its memory directly. Do not try to use
+   * olsr_memcookie_malloc() here.
+   */
+  h = olsr_malloc(sizeof(*h), "Log handler");
+  h->handler = handler;
+  h->bitmask_ptr = mask;
+
+  list_add_tail(&log_handler_list, &h->node);
   olsr_log_updatemask();
+
+  return h;
 }
 
 /**
@@ -165,19 +173,12 @@ olsr_log_addhandler(void (*handler) (enum log_severity, enum log_source, bool,
  * @param handler pointer to handler function
  */
 void
-olsr_log_removehandler(void (*handler) (enum log_severity, enum log_source, bool, const char *, int, char *, int, int))
+olsr_log_removehandler(struct log_handler_entry *h)
 {
-  int i;
-  for (i = 0; i < log_handler_count; i++) {
-    if (handler == log_handler[i].handler) {
-      if (i < log_handler_count - 1) {
-        memmove(&log_handler[i], &log_handler[i + 1], (log_handler_count - i - 1) * sizeof(*log_handler));
-      }
-      log_handler_count--;
-    }
-  }
-
+  list_remove(&h->node);
   olsr_log_updatemask();
+
+  free(h);
 }
 
 /**
@@ -188,20 +189,47 @@ olsr_log_removehandler(void (*handler) (enum log_severity, enum log_source, bool
 void
 olsr_log_updatemask(void)
 {
-  int i, j, k;
+  int i, j;
+  struct log_handler_entry *h, *iterator;
 
-  for (k = 0; k < LOG_SEVERITY_COUNT; k++) {
-    for (j = 0; j < LOG_SOURCE_COUNT; j++) {
-      log_global_mask[k][j] = olsr_cnf->log_event[k][j];
+  /* first copy bitmasks to internal memory */
+  FOR_ALL_LOGHANDLERS(h, iterator) {
+    memcpy (&h->int_bitmask, h->bitmask_ptr, sizeof(h->int_bitmask));
+  }
 
-      for (i = 0; i < log_handler_count; i++) {
-        if (log_handler[i].bitmask != NULL && (*(log_handler[i].bitmask))[k][j]) {
-          log_global_mask[k][j] = true;
-          break;
+  /* second propagate source ALL to all other sources for each logger */
+  FOR_ALL_LOGHANDLERS(h, iterator) {
+    for (j = 0; j < LOG_SEVERITY_COUNT; j++) {
+      if (h->int_bitmask[j][LOG_ALL]) {
+        for (i = 0; i < LOG_SOURCE_COUNT; i++) {
+          h->int_bitmask[j][i] = true;
         }
       }
     }
   }
+
+  /* third, propagate events from debug to info to warn to error */
+  FOR_ALL_LOGHANDLERS(h, iterator) {
+    for (j = 0; j < LOG_SOURCE_COUNT; j++) {
+      bool active = false;
+
+      for (i = 0; i < LOG_SEVERITY_COUNT; i++) {
+        active |= h->int_bitmask[i][j];
+        h->int_bitmask[i][j] = active;
+      }
+    }
+  }
+
+  /* finally calculate the global logging bitmask */
+  for (j = 0; j < LOG_SEVERITY_COUNT; j++) {
+    for (i = 0; i < LOG_SOURCE_COUNT; i++) {
+      log_global_mask[j][i] = false;
+
+      FOR_ALL_LOGHANDLERS(h, iterator) {
+        log_global_mask[j][i] |= h->int_bitmask[j][i];
+      }
+    }
+  }
 }
 
 /**
@@ -219,8 +247,9 @@ void
 olsr_log(enum log_severity severity, enum log_source source, bool no_header, const char *file, int line, const char *format, ...)
 {
   static char logbuffer[LOGBUFFER_SIZE];
+  struct log_handler_entry *h, *iterator;
   va_list ap;
-  int p1 = 0, p2 = 0, p3 = 0, i;
+  int p1 = 0, p2 = 0, p3 = 0;
   struct tm now, *tm_ptr;
   struct timeval timeval;
 
@@ -264,46 +293,45 @@ olsr_log(enum log_severity severity, enum log_source source, bool no_header, con
   }
 
   /* call all log handlers */
-  for (i = 0; i < log_handler_count; i++) {
-    log_handler[i].handler(severity, source, no_header, file, line, logbuffer, p1, p2-p1);
+  FOR_ALL_LOGHANDLERS(h, iterator) {
+    if (h->int_bitmask[severity][source]) {
+      h->handler(severity, source, no_header, file, line, logbuffer, p1, p2-p1);
+    }
   }
   va_end(ap);
 }
 
 static void
-olsr_log_stderr(enum log_severity severity, enum log_source source,
+olsr_log_stderr(enum log_severity severity __attribute__ ((unused)),
+                enum log_source source __attribute__ ((unused)),
                 bool no_header __attribute__ ((unused)),
                 const char *file __attribute__ ((unused)), int line __attribute__ ((unused)),
                 char *buffer,
                 int timeLength __attribute__ ((unused)),
                 int prefixLength __attribute__ ((unused)))
 {
-  if (olsr_cnf->log_event[severity][source]) {
-    fprintf(stderr, "%s\n", buffer);
-  }
+  fprintf(stderr, "%s\n", buffer);
 }
 
 static void
-olsr_log_file(enum log_severity severity, enum log_source source,
+olsr_log_file(enum log_severity severity __attribute__ ((unused)),
+              enum log_source source __attribute__ ((unused)),
               bool no_header __attribute__ ((unused)),
               const char *file __attribute__ ((unused)), int line __attribute__ ((unused)),
               char *buffer,
               int timeLength __attribute__ ((unused)),
               int prefixLength __attribute__ ((unused)))
 {
-  if (olsr_cnf->log_event[severity][source]) {
-    fprintf(log_fileoutput, "%s\n", buffer);
-  }
+  fprintf(log_fileoutput, "%s\n", buffer);
 }
 
 static void
-olsr_log_syslog(enum log_severity severity, enum log_source source,
+olsr_log_syslog(enum log_severity severity __attribute__ ((unused)),
+                enum log_source source __attribute__ ((unused)),
                 bool no_header __attribute__ ((unused)),
                 const char *file __attribute__ ((unused)), int line __attribute__ ((unused)),
                 char *buffer, int timeLength,
                 int prefixLength __attribute__ ((unused)))
 {
-  if (olsr_cnf->log_event[severity][source]) {
-    os_printline(severity, &buffer[timeLength]);
-  }
+  os_printline(severity, &buffer[timeLength]);
 }
index 8092734..5578e9c 100644 (file)
@@ -46,7 +46,6 @@
 #include "olsr_cfg_data.h"
 
 #define LOGBUFFER_SIZE 1024
-#define MAX_LOG_HANDLER 8
 
 /**
  * these four macros should be used to generate OLSR logging output
 #define OLSR_ERROR_NH(source, format, args...) do { if (log_global_mask[SEVERITY_ERR][source]) olsr_log(SEVERITY_ERR, source, true, __FILE__, __LINE__, format, ##args); } while(0)
 #endif
 
+struct log_handler_entry {
+  struct list_entity node;
+  void (*handler)(enum log_severity, enum log_source,
+      bool, const char *, int, char *, int, int);
+
+  /* pointer to handlers own bitmask */
+  bool(*bitmask_ptr)[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT];
+
+  /* internal bitmask copy */
+  bool int_bitmask[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT];
+};
+
 void EXPORT(olsr_log_init) (void);
 void EXPORT(olsr_log_cleanup) (void);
-void EXPORT(olsr_log_addhandler) (void (*handler) (enum log_severity, enum log_source, bool,
+struct log_handler_entry * EXPORT(olsr_log_addhandler) (void (*handler) (enum log_severity, enum log_source, bool,
                                                    const char *, int, char *, int, int),
                                   bool(*mask)[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT]);
-void EXPORT(olsr_log_removehandler) (void (*handler) (enum log_severity, enum log_source, bool,
-    const char *, int, char *, int, int));
+void EXPORT(olsr_log_removehandler) (struct log_handler_entry *);
 void EXPORT(olsr_log_updatemask) (void);
 
 void EXPORT(olsr_log) (enum log_severity, enum log_source, bool, const char *, int, const char *, ...)