Author: aconway
Date: Fri May 23 01:28:24 2014
New Revision: 1596996

URL: http://svn.apache.org/r1596996
Log:
DISPATCH-16: Fix default logging to stdout, broken in prevoius commit.

Other fixes
- Get rid of string literals.
- lowercase levels: consistent with qpidd and syslog.
- timestamp config working, better boolean configuration.

Modified:
    qpid/dispatch/trunk/python/qpid_dispatch_internal/config/parser.py
    qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py
    qpid/dispatch/trunk/python/qpid_dispatch_internal/router/engine.py
    qpid/dispatch/trunk/src/config.c
    qpid/dispatch/trunk/src/log.c
    qpid/dispatch/trunk/tests/system_tests_broker.py

Modified: qpid/dispatch/trunk/python/qpid_dispatch_internal/config/parser.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch_internal/config/parser.py?rev=1596996&r1=1596995&r2=1596996&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/config/parser.py 
(original)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/config/parser.py Fri May 
23 01:28:24 2014
@@ -148,7 +148,7 @@ class SchemaSection:
       if k not in kv_map:
         if self.is_mandatory(k):
           raise Exception("In section '%s', missing mandatory key '%s'" % 
(self.name, k))
-        else:
+        elif self.default_value(k) is not None:
           copy[k] = self.default_value(k)
     for k,v in kv_map.items():
       if k not in self.values:
@@ -342,12 +342,18 @@ class DispatchConfig:
     return long(value)
 
 
+  TRUTH_VALUES= {"yes":True, "true":True, "on":True, "1":True,
+                 "no":None, "false":None, "off":None, "0":None}
+
   def value_bool(self, section, idx, key):
     """
     Return the boolean value for the key in the idx'th item in the section.
     """
     value = self._value(section, idx, key)
-    if value:
-      if str(value) != "no":
-        return True
-    return None
+    if (isinstance(value, basestring)):
+      if value.lower() in TRUTH_VALUES:
+        return TRUTH_VALUES[value.lower()]
+      else:
+        raise ValueError("invalid boolean value '%s'"%value)
+    else:
+      return bool(value) or None

Modified: qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py?rev=1596996&r1=1596995&r2=1596996&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py 
(original)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py Fri May 
23 01:28:24 2014
@@ -89,8 +89,8 @@ config_schema = {
     }),
     'log' : (False, {
         'module' : (str, None, 'M', None, None),
-        'level'  : (str, None, '', 'INFO', ['NONE', 'TRACE', 'DEBUG', 'INFO', 
'NOTICE', 'WARNING', 'ERROR', 'CRITICAL']),
-       'timestamp' : (bool, None, '', True, None),
+        'level'  : (str, None, '', 'info', ['none', 'trace', 'debug', 'info', 
'notice', 'warning', 'error', 'critical']),
+       'timestamp' : (bool, None, '', None, None),
        'output'   : (str, None, '', None, None), # File name or 'stderr' or 
'syslog'
     })
 }

Modified: qpid/dispatch/trunk/python/qpid_dispatch_internal/router/engine.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch_internal/router/engine.py?rev=1596996&r1=1596995&r2=1596996&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/router/engine.py 
(original)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/router/engine.py Fri May 
23 01:28:24 2014
@@ -55,7 +55,7 @@ class RouterEngine:
         ##
         self.domain         = "domain"
         self.router_adapter = router_adapter
-        self.log_adapter    = LogAdapter("dispatch.router")
+        self.log_adapter    = LogAdapter("ROUTER")
         self.io_adapter     = IoAdapter(self, ("qdrouter", "qdhello"))
         self.max_routers    = max_routers
         self.id             = router_id

Modified: qpid/dispatch/trunk/src/config.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/config.c?rev=1596996&r1=1596995&r2=1596996&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/config.c (original)
+++ qpid/dispatch/trunk/src/config.c Fri May 23 01:28:24 2014
@@ -224,10 +224,9 @@ static PyObject *item_value(const qd_dis
 bool qd_config_item_exists(const qd_dispatch_t *dispatch, const char *section, 
int index, const char* key)
 {
     PyObject *pResult = item_value(dispatch, section, index, key, 
"value_string");
-    bool exists = pResult;
-    if (pResult) {
+    bool exists = pResult && pResult != Py_None;
+    if (pResult)
         Py_DECREF(pResult);
-    }
     return exists;
 }
 

Modified: qpid/dispatch/trunk/src/log.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/log.c?rev=1596996&r1=1596995&r2=1596996&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/log.c (original)
+++ qpid/dispatch/trunk/src/log.c Fri May 23 01:28:24 2014
@@ -33,6 +33,10 @@
 #define LIST_MAX 1000
 #define LOG_MAX 640
 
+typedef struct qd_log_source_t qd_log_source_t;
+static qd_log_source_t      *default_log_source=0;
+static qd_log_source_t      *logging_log_source=0;
+
 int qd_log_max_len() { return TEXT_MAX; }
 
 typedef struct qd_log_entry_t qd_log_entry_t;
@@ -51,60 +55,75 @@ ALLOC_DECLARE(qd_log_entry_t);
 ALLOC_DEFINE(qd_log_entry_t);
 
 DEQ_DECLARE(qd_log_entry_t, qd_log_list_t);
+static qd_log_list_t         entries;
+
+static void qd_log_entry_free_lh(qd_log_entry_t* entry) {
+    DEQ_REMOVE(entries, entry);
+    free(entry->file);
+    free_qd_log_entry_t(entry);
+}
 
 // Ref-counted log sink, may be shared by several sources.
-typedef struct qd_log_sink_t {
+typedef struct log_sink_t {
     int refcount;
     char *name;
     bool syslog;
     FILE *file;
-    DEQ_LINKS(struct qd_log_sink_t);
-} qd_log_sink_t;
+    DEQ_LINKS(struct log_sink_t);
+} log_sink_t;
+
+DEQ_DECLARE(log_sink_t, log_sink_list_t);
 
-DEQ_DECLARE(qd_log_sink_t, qd_log_sink_list_t);
+static log_sink_list_t sink_list;
 
-static qd_log_sink_list_t log_sinks;
+static const char* SINK_STDERR = "stderr";
+static const char* SINK_SYSLOG = "syslog";
+static const char* SOURCE_DEFAULT = "DEFAULT";
+static const char* SOURCE_LOGGING = "LOGGING";
 
-static qd_log_sink_t* find_log_sink(const char* name) {
-    qd_log_sink_t* sink = DEQ_HEAD(log_sinks);
+static log_sink_t* find_log_sink_lh(const char* name) {
+    log_sink_t* sink = DEQ_HEAD(sink_list);
     DEQ_FIND(sink, strcmp(sink->name, name) == 0);
     return sink;
 }
 
-qd_log_sink_t* qd_log_sink(const char* name) {
-    qd_log_sink_t* sink = find_log_sink(name);
+static log_sink_t* log_sink_lh(const char* name) {
+    log_sink_t* sink = find_log_sink_lh(name);
     if (sink) 
        sink->refcount++;
     else {
-       sink = NEW(qd_log_sink_t);
-       *sink = (qd_log_sink_t){ 1, strdup(name), };
-       if (strcmp(name, "stderr") == 0) {
+       sink = NEW(log_sink_t);
+       *sink = (log_sink_t){ 1, strdup(name), };
+       if (strcmp(name, SINK_STDERR) == 0) {
            sink->file = stderr;
        }
-       else if (strcmp(name, "syslog") == 0) {
+       else if (strcmp(name, SINK_SYSLOG) == 0) {
            openlog(0, 0, LOG_DAEMON);
            sink->syslog = true;
        }
        else {
            sink->file = fopen(name, "w");
            if (!sink->file) {
-               char msg[LOG_MAX];
+               char msg[TEXT_MAX];
                snprintf(msg, sizeof(msg), "Failed to open log file '%s'", 
name);
                perror(msg);
-               exit(1);                /* TODO aconway 2014-05-22: better 
error handling */
+               exit(1);
            }
        }
-       DEQ_INSERT_TAIL(log_sinks, sink);
+       DEQ_INSERT_TAIL(sink_list, sink);
     }
     return sink;
 }
 
-void qd_log_sink_free(qd_log_sink_t* sink) {
+// Must hold the log_source_lock
+static void log_sink_free_lh(log_sink_t* sink) {
     if (!sink) return;
     assert(sink->refcount);
     if (--sink->refcount == 0) {
+       DEQ_REMOVE(sink_list, sink);
        free(sink->name);
-       if (sink->file && sink->file != stderr) fclose(sink->file);
+       if (sink->file && sink->file != stderr)
+           fclose(sink->file);
        if (sink->syslog) closelog();
        free(sink);
     }
@@ -116,56 +135,61 @@ struct qd_log_source_t {
     int mask;
     int timestamp;
     bool syslog;
-    qd_log_sink_t *sink;
+    log_sink_t *sink;
 };
 
 DEQ_DECLARE(qd_log_source_t, qd_log_source_list_t);
 
-
-static qd_log_list_t         entries;
 static sys_mutex_t          *log_lock = 0;
 static sys_mutex_t          *log_source_lock = 0;
 static qd_log_source_list_t  source_list;
-static qd_log_source_t      *default_log_source=0;
-static qd_log_source_t      *logging_log_source=0;
 
-static const int nlevels = 7;
-static const int level_bits[] ={QD_LOG_TRACE, QD_LOG_DEBUG, QD_LOG_INFO, 
QD_LOG_NOTICE, QD_LOG_WARNING, QD_LOG_ERROR, QD_LOG_CRITICAL};
-static const char* level_names[] = {"TRACE", "DEBUG", "INFO", "NOTICE", 
"WARNING", "ERROR", "CRITICAL"};
-static const int level_syslog_priorities[] = {LOG_DEBUG, LOG_DEBUG, LOG_INFO, 
LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT};
-static const int all_bits = ((QD_LOG_CRITICAL-1) | QD_LOG_CRITICAL);
-
-static int level_index(int level) {
-    int i = 0;
-    while (i < nlevels && level_bits[i] != level) ++i;
-    return (i == nlevels) ? -1 : i;
-}
-
-static const char *level_str(int level) {
-    int i = level_index(level);
-    return i >= 0 ? level_names[i] : "NONE";
-}
-
-static int level_syslog(int level) {
-    int i = level_index(level);
-    return i >= 0 ? level_syslog_priorities[i] : LOG_NOTICE;
-}
-
-static int get_mask(const char *level) {
-    if (strcasecmp(level, "NONE") == 0) return 0;
-    int i = 0;
-    while (i < nlevels && strcasecmp(level_names[i], level) != 0) ++i;
-    if (i == nlevels) {
-       qd_log(logging_log_source, QD_LOG_ERROR, "'%s' is not a valid log 
level. Should be one of {NONE, TRACE, DEBUG, INFO, NOTICE, WARNING, ERROR, 
CRITICAL}. Defaulting to INFO", level);
-       return get_mask("INFO");
+typedef enum {NONE, TRACE, DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, 
N_LEVELS} level_index_t;
+typedef struct level {
+    const char* name;
+    int bit;                   // QD_LOG bit
+    int mask;                  // Bit or higher
+    const int syslog;
+} level;
+#define ALL_BITS (QD_LOG_CRITICAL | (QD_LOG_CRITICAL-1))
+#define LEVEL(name, QD_LOG, SYSLOG) { name, QD_LOG,  ALL_BITS & ~(QD_LOG-1), 
SYSLOG }
+static level levels[] = {
+    {"none", 0, -1, 0},
+    LEVEL("trace",    QD_LOG_TRACE, LOG_DEBUG), /* syslog has no trace level */
+    LEVEL("debug",    QD_LOG_DEBUG, LOG_DEBUG),
+    LEVEL("info",     QD_LOG_INFO, LOG_INFO),
+    LEVEL("notice",   QD_LOG_NOTICE, LOG_NOTICE),
+    LEVEL("warning",  QD_LOG_WARNING, LOG_WARNING),
+    LEVEL("error",    QD_LOG_ERROR, LOG_ERR),
+    LEVEL("critical", QD_LOG_CRITICAL, LOG_CRIT)
+};
+static const char level_names[TEXT_MAX]; /* Set up in qd_log_initialize */
+
+static const level* level_for_bit(int bit) {
+    level_index_t i = 0;
+    while (i < N_LEVELS && levels[i].bit != bit) ++i;
+    if (i == N_LEVELS) {
+       qd_log(logging_log_source, QD_LOG_ERROR, "'%d' is not a valid log level 
bit. Defaulting to %s", bit, levels[INFO].name);
+       i = INFO;
+       assert(0);
     }
-    return  all_bits & ~(level_bits[i]-1);
+    return &levels[i];
+}
+
+static const level* level_for_name(const char *name) {
+    level_index_t i = 0;
+    while (i < N_LEVELS && strcasecmp(levels[i].name, name) != 0) ++i;
+    if (i == N_LEVELS) {
+       qd_log(logging_log_source, QD_LOG_ERROR, "'%s' is not a valid log 
level. Should be one of {%s}. Defaulting to %s", name, level_names, 
levels[INFO].name);
+       i = INFO;
+    }
+    return &levels[i];
 }
 
 /// Caller must hold log_source_lock
 static qd_log_source_t* lookup_log_source_lh(const char *module)
 {
-    if (strcasecmp(module, "DEFAULT") == 0)
+    if (strcasecmp(module, SOURCE_DEFAULT) == 0)
        return default_log_source;
     qd_log_source_t *src = DEQ_HEAD(source_list);
     DEQ_FIND(src, strcasecmp(module, src->module) == 0);
@@ -174,19 +198,30 @@ static qd_log_source_t* lookup_log_sourc
 
 static void write_log(int level, qd_log_source_t *log_source, const char *fmt, 
...)
 {
-    qd_log_sink_t* sink = log_source->sink ? log_source->sink : 
default_log_source->sink;
+    log_sink_t* sink = log_source->sink ? log_source->sink : 
default_log_source->sink;
 
     if (!sink) return;
 
-    /* FIXME aconway 2014-05-22: move output logic to sink */
     char log_str[LOG_MAX];
     va_list arglist;
     va_start(arglist, fmt);
     vsnprintf(log_str, LOG_MAX, fmt, arglist);
     va_end(arglist);
 
-    if (sink->file) fputs(log_str, sink->file);
-    if (sink->syslog) syslog(level_syslog(level), "%s", log_str);
+    if (sink->file) {
+       if (fputs(log_str, sink->file) == EOF) {
+           char msg[TEXT_MAX];
+           snprintf(msg, sizeof(msg), "Cannot write log output to '%s'", 
sink->name);
+           perror(msg);
+           exit(1);
+       };
+       fflush(sink->file);
+    }
+    if (sink->syslog) {
+       int syslog_level = level_for_bit(level)->syslog;
+       if (syslog_level != -1)
+           syslog(syslog_level, "%s", log_str);
+    }
 }
 
 /// Caller must hold the log_source_lock
@@ -215,8 +250,9 @@ qd_log_source_t *qd_log_source(const cha
     return src;
 }
 
-void qd_log_source_free(qd_log_source_t* src) {
-    qd_log_sink_free(src->sink);
+static void qd_log_source_free_lh(qd_log_source_t* src) {
+    DEQ_REMOVE_HEAD(source_list);
+    log_sink_free_lh(src->sink);
     free(src);
 }
 
@@ -239,23 +275,25 @@ void qd_log_impl(qd_log_source_t *source
     time(&entry->time);
 
     char ctime[100];
+    ctime[0] = '\0';
+    bool timestamp = (source->timestamp == -1) ?
+                     default_log_source->timestamp : source->timestamp;
+    assert(timestamp != -1);
+    if (timestamp) {
+       ctime_r(&entry->time, ctime);
+       ctime[24] = '\0';
+       strcat(ctime, " ");
+    }
     va_list ap;
-
     va_start(ap, fmt);
     vsnprintf(entry->text, TEXT_MAX, fmt, ap);
     va_end(ap);
-    ctime_r(&entry->time, ctime);
-    ctime[24] = '\0';
-    write_log(level, source, "%s %s (%s) %s\n", ctime, entry->module, 
level_str(level), entry->text);
+    write_log(level, source, "%s%s (%s) %s\n", ctime, entry->module, 
level_for_bit(level)->name, entry->text);
 
     sys_mutex_lock(log_lock);
     DEQ_INSERT_TAIL(entries, entry);
-    if (DEQ_SIZE(entries) > LIST_MAX) {
-        entry = DEQ_HEAD(entries);
-        DEQ_REMOVE_HEAD(entries);
-        free(entry->file);
-        free_qd_log_entry_t(entry);
-    }
+    if (DEQ_SIZE(entries) > LIST_MAX)
+       qd_log_entry_free_lh(entry);
     sys_mutex_unlock(log_lock);
 }
 
@@ -263,31 +301,31 @@ void qd_log_initialize(void)
 {
     DEQ_INIT(entries);
     DEQ_INIT(source_list);
+    DEQ_INIT(sink_list);
+    strcpy((char*)level_names, levels[NONE].name);
+    for (level_index_t i = NONE+1; i < N_LEVELS; ++i) {
+       strcat((char*)level_names, ", ");
+       strcat((char*)level_names, levels[i].name);
+    }
     log_lock = sys_mutex();
     log_source_lock = sys_mutex();
 
-    default_log_source = NEW(qd_log_source_t);
-    memset(default_log_source, 0, sizeof(qd_log_source_t));
-    default_log_source->module = "DEFAULT";
+    default_log_source = qd_log_source(SOURCE_DEFAULT);
     // Only report errors until we have configured the logging system.
-    default_log_source->mask = get_mask("ERROR");
+    default_log_source->mask = levels[ERROR].mask;
     default_log_source->timestamp = 1;
-    default_log_source->sink = 0;
-    logging_log_source = qd_log_source("LOGGING");
+    default_log_source->sink = log_sink_lh(SINK_STDERR);
+    logging_log_source = qd_log_source(SOURCE_LOGGING);
 }
 
 
 void qd_log_finalize(void) {
-    for (qd_log_source_t *src = DEQ_HEAD(source_list); src != 0; src = 
DEQ_HEAD(source_list)) {
-        DEQ_REMOVE_HEAD(source_list);
-        qd_log_source_free(src);
-    }
-
-    for (qd_log_entry_t *entry = DEQ_HEAD(entries); entry; entry = 
DEQ_HEAD(entries)) {
-        DEQ_REMOVE_HEAD(entries);
-        free(entry->file);
-        free_qd_log_entry_t(entry);
-    }
+    while (DEQ_HEAD(source_list))
+       qd_log_source_free_lh(DEQ_HEAD(source_list));
+    while (DEQ_HEAD(entries))
+        qd_log_entry_free_lh(DEQ_HEAD(entries));
+    while (DEQ_HEAD(sink_list))
+       log_sink_free_lh(DEQ_HEAD(sink_list));
 }
 
 ///@return 0,1 or -1 if not present
@@ -303,18 +341,23 @@ void qd_log_configure(const qd_dispatch_
 {
     if (!qd) return;
     // Default to INFO now that we are configuring the logging system.
-    default_log_source->mask = get_mask("INFO");
+    default_log_source->mask = levels[INFO].mask;
     int count = qd_config_item_count(qd, "log");
     for (int i=0; i < count; i++) {
        sys_mutex_lock(log_source_lock);
        const char* module = ITEM_STRING("module");
        qd_log_source_t *src = qd_log_source_lh(module);
-       src->module = ITEM_STRING("module");
-       src->mask = get_mask(ITEM_STRING("level"));
-       src->timestamp = ITEM_OPT_BOOL("timestamp");
-
+       src->mask = level_for_name(ITEM_STRING("level"))->mask;
+       int timestamp = ITEM_OPT_BOOL("timestamp");
+       if (timestamp != -1) src->timestamp = timestamp;
        const char* output = ITEM_STRING("output");
-       if (output) src->sink = qd_log_sink(output);
+       if (output) {
+           log_sink_t* old_sink = src->sink;
+           src->sink = log_sink_lh(output);
+           log_sink_free_lh(old_sink); /* DEFAULT source may already have a 
sink */
+           if (src->sink->syslog) /* Timestamp off for syslog. */
+               src->timestamp = 0;
+       }
        sys_mutex_unlock(log_source_lock);
     }
     qd_log(logging_log_source, QD_LOG_INFO, "Logging system configured");

Modified: qpid/dispatch/trunk/tests/system_tests_broker.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_broker.py?rev=1596996&r1=1596995&r2=1596996&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/system_tests_broker.py (original)
+++ qpid/dispatch/trunk/tests/system_tests_broker.py Fri May 23 01:28:24 2014
@@ -55,9 +55,9 @@ class DistributedQueueTest(system_test.T
     def common_router_conf(self, name, mode='standalone'):
         """Common router configuration for the tests"""
         return Qdrouterd.Config([
-            ('log', {'module':'DEFAULT', 'level':'INFO', 
'output':name+".log"}),
-            ('log', {'module':'ROUTER', 'level':'TRACE'}),
-            ('log', {'module':'MESSAGE', 'level':'TRACE'}),
+            # ('log', {'module':'DEFAULT', 'level':'info', 
'output':name+".log"}),
+            # ('log', {'module':'ROUTER', 'level':'trace'}),
+            # ('log', {'module':'MESSAGE', 'level':'trace'}),
             ('container', {'container-name':name}),
             ('router', {'mode': mode, 'router-id': name})
         ])
@@ -75,7 +75,6 @@ class DistributedQueueTest(system_test.T
         for b, a in zip(r, cycle(send_addresses)):
             msgr.put(message(address=a, body=b))
         msgr.flush()
-        # FIXME aconway 2014-05-20: From which subscription?
         messages = sorted(msgr.fetch().body for i in r)
         msgr.flush()
         self.assertEqual(r, messages)



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to