Author: aconway
Date: Thu May 22 05:59:00 2014
New Revision: 1596761
URL: http://svn.apache.org/r1596761
Log:
DISPATCH-16: Added support for logging to a file or to syslog. Updated
qdconfigd.conf man page.
Modified:
qpid/dispatch/trunk/doc/man/qdrouterd.conf.5.in
qpid/dispatch/trunk/include/qpid/dispatch/ctools.h
qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py
qpid/dispatch/trunk/src/log.c
qpid/dispatch/trunk/tests/system_tests_broker.py
Modified: qpid/dispatch/trunk/doc/man/qdrouterd.conf.5.in
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdrouterd.conf.5.in?rev=1596761&r1=1596760&r2=1596761&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdrouterd.conf.5.in (original)
+++ qpid/dispatch/trunk/doc/man/qdrouterd.conf.5.in Thu May 22 05:59:00 2014
@@ -124,6 +124,16 @@ Only if fanout is single. One of "close
to an address will always be delivered to the closest (lowest cost) subscribed
consumer.
Spread bias will distribute the messages across subscribers in an
approximately even
manner.
+.SS "'log' section"
+Specifies logging for a router module.
+.IP module
+The module name, e.g. ROUTER, MESSAGE, SERVER, AGENT, CONTAINER, CONFIG. The
special module name DEFAULT specifies logging for any modules that don't have
explicit log sections.
+.IP level
+One of NONE, TRACE, DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL. Indicates
the minimum
+logging level for the module. E.g. WARNING means log WARNING, ERROR and
CRITICAL messages.
+TRACE logs all messages. NONE disables logging for the module.
+.IP output
+Where to send log messages. Can be 'stderr', 'syslog' or a file name.
.\" XXX .SH EXAMPLES
.SH FILES
.I /etc/qpid-dispatch/qdrouterd.conf
Modified: qpid/dispatch/trunk/include/qpid/dispatch/ctools.h
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/include/qpid/dispatch/ctools.h?rev=1596761&r1=1596760&r2=1596761&view=diff
==============================================================================
--- qpid/dispatch/trunk/include/qpid/dispatch/ctools.h (original)
+++ qpid/dispatch/trunk/include/qpid/dispatch/ctools.h Thu May 22 05:59:00 2014
@@ -28,6 +28,8 @@
#define NEW_ARRAY(t,n) (t*) malloc(sizeof(t)*(n))
#define NEW_PTR_ARRAY(t,n) (t**) malloc(sizeof(t*)*(n))
+#define ZERO(p) memset(p, 0, sizeof(*p))
+
#define DEQ_DECLARE(i,d) typedef struct { \
i *head; \
i *tail; \
@@ -44,6 +46,11 @@
#define DEQ_SIZE(d) ((d).size)
#define DEQ_NEXT(i) (i)->next
#define DEQ_PREV(i) (i)->prev
+/**
+ *@pre ptr points to first element of deq
+ *@post ptr points to first element of deq that passes test, or 0. Test should
involve ptr.
+ */
+#define DEQ_FIND(ptr, test) while((ptr) && !(test)) ptr = DEQ_NEXT(ptr);
#define DEQ_INSERT_HEAD(d,i) \
do { \
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=1596761&r1=1596760&r2=1596761&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py
(original)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/config/schema.py Thu May
22 05:59:00 2014
@@ -91,10 +91,7 @@ config_schema = {
'module' : (str, None, 'M', None, None),
'level' : (str, None, '', 'INFO', ['NONE', 'TRACE', 'DEBUG', 'INFO',
'NOTICE', 'WARNING', 'ERROR', 'CRITICAL']),
'timestamp' : (bool, None, '', True, None),
- 'stderr' : (bool, None, '', True, None),
- 'syslog' : (bool, None, '', False, None),
- 'file' : (str, None, '', None, None), # File name
- 'max-size' : (int, None, "", 1024, None), # Max file size
+ 'output' : (str, None, '', None, None), # File name or 'stderr' or
'syslog'
})
}
Modified: qpid/dispatch/trunk/src/log.c
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/log.c?rev=1596761&r1=1596760&r2=1596761&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/log.c (original)
+++ qpid/dispatch/trunk/src/log.c Thu May 22 05:59:00 2014
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
+#include <syslog.h>
#define TEXT_MAX 512
#define LIST_MAX 1000
@@ -51,16 +52,71 @@ ALLOC_DEFINE(qd_log_entry_t);
DEQ_DECLARE(qd_log_entry_t, qd_log_list_t);
+// Ref-counted log sink, may be shared by several sources.
+typedef struct qd_log_sink_t {
+ int refcount;
+ char *name;
+ bool syslog;
+ FILE *file;
+ DEQ_LINKS(struct qd_log_sink_t);
+} qd_log_sink_t;
+
+DEQ_DECLARE(qd_log_sink_t, qd_log_sink_list_t);
+
+static qd_log_sink_list_t log_sinks;
+
+static qd_log_sink_t* find_log_sink(const char* name) {
+ qd_log_sink_t* sink = DEQ_HEAD(log_sinks);
+ 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);
+ 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->file = stderr;
+ }
+ else if (strcmp(name, "syslog") == 0) {
+ openlog(0, 0, LOG_DAEMON);
+ sink->syslog = true;
+ }
+ else {
+ sink->file = fopen(name, "w");
+ if (!sink->file) {
+ char msg[LOG_MAX];
+ snprintf(msg, sizeof(msg), "Failed to open log file '%s'",
name);
+ perror(msg);
+ exit(1); /* TODO aconway 2014-05-22: better
error handling */
+ }
+ }
+ DEQ_INSERT_TAIL(log_sinks, sink);
+ }
+ return sink;
+}
+
+void qd_log_sink_free(qd_log_sink_t* sink) {
+ if (!sink) return;
+ assert(sink->refcount);
+ if (--sink->refcount == 0) {
+ free(sink->name);
+ if (sink->file && sink->file != stderr) fclose(sink->file);
+ if (sink->syslog) closelog();
+ free(sink);
+ }
+}
+
struct qd_log_source_t {
DEQ_LINKS(qd_log_source_t);
const char *module;
int mask;
int timestamp;
- int print;
- int stderr;
- char* file;
- int syslog;
- //FILE *file;
+ bool syslog;
+ qd_log_sink_t *sink;
};
DEQ_DECLARE(qd_log_source_t, qd_log_source_list_t);
@@ -74,17 +130,26 @@ static qd_log_source_t *default_log
static qd_log_source_t *logging_log_source=0;
static const int nlevels = 7;
-static const char* level_names[]={"TRACE", "DEBUG", "INFO", "NOTICE",
"WARNING", "ERROR", "CRITICAL"};
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 const char *level_str(int level) {
- if (level == 0) return "NONE";
+static int level_index(int level) {
int i = 0;
while (i < nlevels && level_bits[i] != level) ++i;
- return (i == nlevels) ? "NONE" : level_names[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;
@@ -103,30 +168,25 @@ static qd_log_source_t* lookup_log_sourc
if (strcasecmp(module, "DEFAULT") == 0)
return default_log_source;
qd_log_source_t *src = DEQ_HEAD(source_list);
- while(src && strcasecmp(module, src->module) != 0)
- src = DEQ_NEXT(src);
+ DEQ_FIND(src, strcasecmp(module, src->module) == 0);
return src;
}
-static void write_log(qd_log_source_t *log_source, const char *fmt, ...)
+static void write_log(int level, qd_log_source_t *log_source, const char *fmt,
...)
{
- int stderr_ = log_source->stderr == -1 ? default_log_source->stderr :
log_source->stderr;
- int syslog = log_source->syslog == -1 ? default_log_source->syslog :
log_source->syslog;
- const char* file = log_source->file == 0 ? default_log_source->file :
log_source->file;
+ qd_log_sink_t* sink = log_source->sink ? log_source->sink :
default_log_source->sink;
- if (!(stderr_ || syslog || file)) return;
+ 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 (stderr_) fputs(log_str, stderr);
- /* FIXME aconway 2014-05-12: unfinished
- if (syslog) ...
- if (file) ...
- */
+ if (sink->file) fputs(log_str, sink->file);
+ if (sink->syslog) syslog(level_syslog(level), "%s", log_str);
}
/// Caller must hold the log_source_lock
@@ -141,9 +201,7 @@ static qd_log_source_t *qd_log_source_lh
log_source->module = module;
log_source->mask = -1;
log_source->timestamp = -1;
- log_source->stderr = -1;
- log_source->syslog = -1;
- log_source->file = 0;
+ log_source->sink = 0;
DEQ_INSERT_TAIL(source_list, log_source);
}
return log_source;
@@ -158,7 +216,7 @@ qd_log_source_t *qd_log_source(const cha
}
void qd_log_source_free(qd_log_source_t* src) {
- free(src->file);
+ qd_log_sink_free(src->sink);
free(src);
}
@@ -188,7 +246,7 @@ void qd_log_impl(qd_log_source_t *source
va_end(ap);
ctime_r(&entry->time, ctime);
ctime[24] = '\0';
- write_log(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_str(level), entry->text);
sys_mutex_lock(log_lock);
DEQ_INSERT_TAIL(entries, entry);
@@ -214,9 +272,7 @@ void qd_log_initialize(void)
// Only report errors until we have configured the logging system.
default_log_source->mask = get_mask("ERROR");
default_log_source->timestamp = 1;
- default_log_source->stderr = 1;
- default_log_source->syslog = 0;
- default_log_source->file = 0;
+ default_log_source->sink = 0;
logging_log_source = qd_log_source("LOGGING");
}
@@ -256,10 +312,9 @@ void qd_log_configure(const qd_dispatch_
src->module = ITEM_STRING("module");
src->mask = get_mask(ITEM_STRING("level"));
src->timestamp = ITEM_OPT_BOOL("timestamp");
- src->stderr = ITEM_OPT_BOOL("stderr");
- src->syslog = ITEM_OPT_BOOL("syslog");
- const char* file = ITEM_STRING("file");
- src->file = file ? strdup(file) : 0;
+
+ const char* output = ITEM_STRING("output");
+ if (output) src->sink = qd_log_sink(output);
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=1596761&r1=1596760&r2=1596761&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/system_tests_broker.py (original)
+++ qpid/dispatch/trunk/tests/system_tests_broker.py Thu May 22 05:59:00 2014
@@ -55,7 +55,7 @@ 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'}),
+ ('log', {'module':'DEFAULT', 'level':'INFO',
'output':name+".log"}),
('log', {'module':'ROUTER', 'level':'TRACE'}),
('log', {'module':'MESSAGE', 'level':'TRACE'}),
('container', {'container-name':name}),
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]