From 551d4aa1be9f4d256df3fadca9a005a0f316adf8 Mon Sep 17 00:00:00 2001
From: bertho <bertho>
Date: Thu, 5 Feb 2009 01:26:26 +0000
Subject: Add a flexible debug interface. Please read the documentation.

---
 server/doc/debug-options.txt  |  66 ++++++++++++++++
 server/src/Makefile.am        |   1 +
 server/src/database.cc        |  31 ++++----
 server/src/debug.cc           | 173 ++++++++++++++++++++++++++++++++++++++++++
 server/src/debug.h            |  83 +++++++++++++++++++-
 server/src/macroparser.cc     |  18 ++---
 server/src/pracrod.cc         |  17 ++++-
 server/src/queryhandler.cc    |  21 ++---
 server/src/tcpsocket.cc       |  25 +++---
 server/src/widgetgenerator.cc |   3 +-
 10 files changed, 380 insertions(+), 58 deletions(-)
 create mode 100644 server/doc/debug-options.txt
 create mode 100644 server/src/debug.cc

diff --git a/server/doc/debug-options.txt b/server/doc/debug-options.txt
new file mode 100644
index 0000000..09ce278
--- /dev/null
+++ b/server/doc/debug-options.txt
@@ -0,0 +1,66 @@
+Note on debug options
+---------------------
+To use the full debug interface, you must configure the application using
+"--with-debug". Otherwise, only messages that also are sent to the log are
+processed.
+
+The debug interface is channelized to allow for selective enabling/disabling of
+messages. The commandline interface uses the -D/--debug option with a
+mandatory argument. The optin is defined is as follows:
+  -D [set[,set]*]?
+A 'set' is a definition for which channel(s) which level of messages are
+requested. Each set can take one of these forms:
+  [+-]all            -- Enable/disable all messages on all channels
+  [+-]?channel       -- Enable/disable all message on 'channel'
+  class[+-]channel   -- Enable/disable message of 'class' on 'channel'
+A 'class' can be one of the following: "fixme", "info", "warn", "err",
+"debug".  A 'channel' is a name that groups messages together and is
+application specific.  Some common channel names are "db" for database
+messages, "socket" for network related issues, "macro" for macro parser,
+"widget" for widget related messages, etc.. The channel name "all" is reserved
+to mean all channels.
+Examples:
+  -D +all,debug-socket
+       Enable all messages except socket debug messages
+
+  -D -all,+db,info+socket
+       Disable all messages except any database messages and socket messages at level info
+
+Classes "err" and "fixme" are enabled by default. The sets in the argument are
+processed in a left-to-right order. Duplicates are processed and can in
+combination with 'all' be very powerful. Your mileage may vary.
+
+The debug interface was /highly/ inspired by the Wine project.
+
+
+
+Programming with debug the interface
+------------------------------------
+There are eight macros in debug.h which support the debug interface. The first
+five are only active when the application is configured with "--with-debug".
+The last three act differently depending on the configuration, where they
+normally log to syslog (FIXME, implement it...) or map to the debug
+equivalents in case of debug configuration.
+
+- PRACRO_FIXME(ch, fmt...)
+- PRACRO_INFO(ch, fmt...)
+- PRACRO_WARN(ch, fmt...)
+- PRACRO_ERR(ch, fmt...)
+- PRACRO_DEBUG(ch, fmt...)
+
+- PRACRO_INFO_LOG(ch, fmt...)
+- PRACRO_WARN_LOG(ch, fmt...)
+- PRACRO_ERR_LOG(ch, fmt...)
+
+Using these macros is just like a printf statement:
+    PRACRO_DEBUG(db, "We selected %d rows from %s.\n", rows, table);
+This example would print something like:
+    debug:db:file.c:123 We selected 12 rows from mytable.
+
+The first block shows the debug class (debug), the channel (db) and the source
+file including the line number where the statement is located in the source.
+
+There are equivalent macros to handle va_list arguments, which are named:
+- PRACRO_*_VA(ch, fmt, va)
+- PRACRO_*_LOG_VA(ch, fmt, va)
+
diff --git a/server/src/Makefile.am b/server/src/Makefile.am
index 7e49e89..7daa3be 100644
--- a/server/src/Makefile.am
+++ b/server/src/Makefile.am
@@ -11,6 +11,7 @@ pracrod_SOURCES = \
 	database.cc \
 	configuration.cc \
 	configurationparser.cc \
+	debug.cc \
 	exception.cc \
 	queryhandler.cc \
 	queryparser.cc \
diff --git a/server/src/database.cc b/server/src/database.cc
index ec1e736..9406e1e 100644
--- a/server/src/database.cc
+++ b/server/src/database.cc
@@ -29,6 +29,7 @@
 #include <config.h>
 #include <stdlib.h>
 
+#include "debug.h"
 
 Database::Database(std::string hostname, std::string user, std::string password)
 #ifndef WITHOUT_DB
@@ -81,18 +82,15 @@ void Database::commit(std::string user,
       }
       ts += ")";
       R = W.exec(ts);
-#ifdef WITH_DEBUG
-    printf("Database::commit: input fields: %d, output fields: %lu\n", fields.size(), R.size());
-#endif/*WITHOUT_DB*/
+      PRACRO_DEBUG(db, "Database::commit: input fields: %d, output fields: %lu\n", fields.size(), R.size());
 
       pqxx::result::const_iterator ri = R.begin();
       // Store known fields
       while(ri != R.end()) {
         pqxx::result::tuple t = *ri;
         std::string name = t[0].c_str();
-#ifdef WITH_DEBUG
-        printf("Storing: %s with value %s\n", name.c_str(), fields[name].c_str());
-#endif/*WITHOUT_DB*/
+
+        PRACRO_DEBUG(db, "Storing: %s with value %s\n", name.c_str(), fields[name].c_str());
 
         ts = "INSERT INTO fields VALUES ("
           " '" + W.esc(oid.str()) + "', "
@@ -106,16 +104,15 @@ void Database::commit(std::string user,
     }
     W.commit();
   } catch(std::exception &e) {
-    printf("Query failed: %s: %s\n", e.what(), ts.c_str());
+    PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str());
   }
 #else
 #ifdef WITH_DEBUG
   std::map< std::string, std::string >::iterator i = fields.begin();
   while(i != fields.end()) {
-    printf("Storing field '%s': '%s'\n", i->first, i->second);
+    PRACRO_DEBUG(db, "Storing field '%s': '%s'\n", i->first, i->second);
     i++;
   }
-
 #endif/*WITH_DEBUG*/
 #endif/*WITHOUT_DB*/
 }
@@ -146,11 +143,11 @@ void Database::putResume(std::string user,
     pqxx::result R = W.exec(ts);
     W.commit();
   } catch(std::exception &e) {
-    printf("Query failed: %s: %s\n", e.what(), ts.c_str());
+    PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str());
   }
 #else
 #ifdef WITH_DEBUG
-  printf("INSERT INTO journal VALUES ('%s', '%s', '%s', '%s', '%s', '%s')\n",
+  PRACRO_DEBUG(db, "INSERT INTO journal VALUES ('%s', '%s', '%s', '%s', '%s', '%s')\n",
          cpr.c_str(),
          macro.c_str(),
          version.c_str(),
@@ -188,11 +185,11 @@ std::string Database::getResume(std::string cpr,
       ri++;
     }
   } catch (std::exception &e) {
-    printf("Query failed: %s: %s\n", e.what(), query.c_str());
+    PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), query.c_str());
   }
 #else
 #ifdef WITH_DEBUG
-  printf("SELECT journal FROM journal WHERE cpr = '%s' AND macro = '%s' ORDER BY timestamp", cpr.c_str(), macro.c_str());
+  PRACRO_DEBUG(db, "SELECT journal FROM journal WHERE cpr = '%s' AND macro = '%s' ORDER BY timestamp", cpr.c_str(), macro.c_str());
 #endif/*WITH_DEBUG*/
 #endif/*WITHOUT_DB*/
   
@@ -240,11 +237,11 @@ Values Database::getValues(std::string cpr,
       ri++;
     }
   } catch (std::exception &e) {
-    printf("Query failed: %s: %s\n", e.what(), query.c_str());
+    PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), query.c_str());
   }
 #else
 #ifdef WITH_DEBUG
-  printf("getValues(%s, <fields...>, %ld) -- not implemented without database...\n", cpr.c_str(), oldest);
+  PRACRO_DEBUG(db, "getValues(%s, <fields...>, %ld) -- not implemented without database...\n", cpr.c_str(), oldest);
 #endif/*WITH_DEBUG*/
 #endif/*WITHOUT_DB*/
 
@@ -269,11 +266,11 @@ bool Database::checkMacro(std::string cpr,
     pqxx::result R = W.exec(query);
     return R.size() != 0;
   } catch(std::exception &e) {
-    printf("Query failed: %s: %s\n", e.what(), query.c_str());
+    PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), query.c_str());
   }
 #else
 #ifdef WITH_DEBUG
-    printf("SELECT oid FROM transactions WHERE cpr = '%s' AND macro = '%s' AND timestamp >= %ld ORDER BY timestamp\n",
+    PRACRO_DEBUG(db, "SELECT oid FROM transactions WHERE cpr = '%s' AND macro = '%s' AND timestamp >= %ld ORDER BY timestamp\n",
       cpr.c_str(), macro.c_str(), oldest);
 #endif/*WITH_DEBUG*/
 #endif/*WITHOUT_DB*/
diff --git a/server/src/debug.cc b/server/src/debug.cc
new file mode 100644
index 0000000..9c2f268
--- /dev/null
+++ b/server/src/debug.cc
@@ -0,0 +1,173 @@
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "debug.h"
+
+#define NELEM(x)	(sizeof(x)/sizeof((x)[0]))
+struct __pracro_debug_channel
+{
+	char		name[16];
+	unsigned	flags;
+};
+
+static const char * const debug_class_str[] = { "fixme", "info", "warn", "err", "debug" };
+#define __PRACRO_DEBUG_CHANNEL_MAX	256
+static struct __pracro_debug_channel debug_channel[__PRACRO_DEBUG_CHANNEL_MAX];
+static unsigned n_debug_channel = 0;
+static unsigned debug_flags = (1 << __pracro_class_err) | (1 << __pracro_class_fixme);
+
+static int __pracro_debug_enabled(const enum __pracro_debug_class cl, const char *ch)
+{
+	unsigned i;
+	for(i = 0; i < n_debug_channel; i++) {
+		if(!strcmp(ch, debug_channel[i].name)) {
+			return debug_channel[i].flags & (1 << cl);
+		}
+	}
+	return debug_flags & (1 << cl);
+}
+
+
+#ifdef WITH_DEBUG
+int __pracro_debug(const char *func, const int line, const enum __pracro_debug_class cl, const char *ch, const char *fmt, ...)
+{
+	int ret = 0;
+	if(__pracro_debug_enabled(cl, ch)) {
+		if((unsigned)cl < NELEM(debug_class_str))
+			ret += fprintf(stderr, "%s:%s:%s:%d ", debug_class_str[(unsigned)cl], ch, func, line);
+		if(fmt) {
+			va_list va;
+			va_start(va, fmt);
+			ret += vfprintf(stderr, fmt, va);
+			va_end(va);
+		}
+	}
+	if(ret)
+		fflush(stderr);
+	return ret;
+}
+
+int __pracro_debug_va(const char *func, const int line, const enum __pracro_debug_class cl, const char *ch, const char *fmt, va_list va)
+{
+	int ret = 0;
+	if(__pracro_debug_enabled(cl, ch)) {
+		if((unsigned)cl < NELEM(debug_class_str))
+			ret += fprintf(stderr, "%s:%s:%s:%d ", debug_class_str[(unsigned)cl], ch, func, line);
+		if(fmt)
+			ret += vfprintf(stderr, fmt, va);
+	}
+	if(ret)
+		fflush(stderr);
+	return ret;
+}
+
+void pracro_debug_init(void)
+{
+}
+
+#else
+
+/* FIXME: should do syslog here... */
+int __pracro_log(const char *func, const int line, const enum __pracro_debug_class cl, const char *ch, const char *fmt, ...)
+{
+	int ret = 0;
+	if(__pracro_debug_enabled(cl, ch)) {
+		if((unsigned)cl < NELEM(debug_class_str))
+			ret += fprintf(stderr, "%s:%s:%s:%d ", debug_class_str[(unsigned)cl], ch, func, line);
+		if(fmt) {
+			va_list va;
+			va_start(va, fmt);
+			ret += vfprintf(stderr, fmt, va);
+			va_end(va);
+		}
+	}
+	return ret;
+}
+
+/* FIXME: should do syslog here... */
+int __pracro_log_va(const char *func, const int line, const enum __pracro_debug_class cl, const char *ch, const char *fmt, va_list va)
+{
+	int ret = 0;
+	if(__pracro_debug_enabled(cl, ch)) {
+		if((unsigned)cl < NELEM(debug_class_str))
+			ret += fprintf(stderr, "%s:%s:%s:%d ", debug_class_str[(unsigned)cl], ch, func, line);
+		if(fmt)
+			ret += vfprintf(stderr, fmt, va);
+	}
+	return ret;
+}
+
+void pracro_debug_init(void)
+{
+}
+
+#endif
+
+/*
+ * fmt := [set[,set]*]*
+ * set := [+-]channel
+ *     |  class[+-]channel
+ *     |  [+-]all
+ */
+void pracro_debug_parse(const char *fmt)
+{
+	char *s;
+	char *next;
+	char *opt;
+
+	if(!(s = strdup(fmt))) return;
+
+	for(opt = s; opt; opt = next) {
+		int set = 0;
+		int clr = 0;
+		unsigned i;
+		if((next = strchr(s, ','))) *next++ = '\0';
+		char *p = opt + strcspn(opt, "+-");
+		if(!*p) p = opt;	/* All chars -> a channel name */
+		if(p > opt) {
+			/* we have a class */
+			for(i = 0; i < NELEM(debug_class_str); i++) {
+				int n = strlen(debug_class_str[i]);
+				if(n != (p - opt)) continue;
+				if(!memcmp(opt, debug_class_str[i], n)) {
+					/* Found the class */
+					if(*p == '+')
+						set = 1 << i;
+					else
+						clr = 1 << i;
+					break;
+				}
+			}
+			if(i == NELEM(debug_class_str)) continue;
+		} else {
+			if(*p == '-')
+				clr = ~0;
+			else
+				set = ~0;
+		}
+		if(*p == '+' || *p == '-') p++;
+		if(!*p) continue;
+		if(!strcmp("all", p)) {
+			debug_flags = (debug_flags & ~clr) | set;
+		} else {
+			if(strlen(p) >= sizeof(debug_channel[0].name)) continue;
+			for(i = 0; i < n_debug_channel; i++) {
+				if(!strcmp(p, debug_channel[i].name)) {
+					debug_channel[i].flags = (debug_channel[i].flags & ~clr) | set;
+					break;
+				}
+			}
+			if(i == n_debug_channel) {
+				strcpy(debug_channel[i].name, p);
+				debug_channel[i].flags = (debug_flags & ~clr) | set;
+				n_debug_channel++;
+			}
+		}
+	}
+	free(s);
+}
+
diff --git a/server/src/debug.h b/server/src/debug.h
index 9c49f67..0e64a27 100644
--- a/server/src/debug.h
+++ b/server/src/debug.h
@@ -27,7 +27,9 @@
 #ifndef __ARTEFACT_DEBUG_H__
 #define __ARTEFACT_DEBUG_H__
 
-#ifdef HAVE_CONFIG
+#include <stdarg.h>
+
+#ifdef HAVE_CONFIG_H
 // For USE_EFENCE
 #include <config.h>
 #ifdef USE_EFENCE
@@ -48,4 +50,83 @@
 #endif/*USE_EFENCE*/
 #endif/*HAVE_CONFIG*/
 
+void pracro_debug_init(void);
+void pracro_debug_parse(const char *fmt);
+
+enum __pracro_debug_class
+{
+	__pracro_class_fixme,
+	__pracro_class_info,
+	__pracro_class_warn,
+	__pracro_class_err,
+	__pracro_class_debug
+};
+
+#ifndef __GNUC__
+#error "Need gcc for special debug macro expansions. Please define for other compilers."
+#endif
+
+#ifdef WITH_DEBUG
+int __pracro_debug(const char *func, const int line, enum __pracro_debug_class cl, const char *ch, const char *fmt, ...) __attribute__((format (printf,5,6)));
+int __pracro_debug_va(const char *func, const int line, enum __pracro_debug_class cl, const char *ch, const char *fmt, va_list va);
+
+/* gcc preprocessor magic ahead */
+#define __PRACRO_DEBUG_PRINT(cl, ch, fmt...)	\
+	do { __pracro_debug(__func__, __LINE__, cl, ch, fmt); } while(0)
+#define __PRACRO_DEBUG_PRINT_VA(cl, ch, fmt, a)	\
+	do { __pracro_debug_va(__func__, __LINE__, cl, ch, fmt, a); } while(0)
+#define __PRACRO_DEBUG(cl, ch, fmt...)		__PRACRO_DEBUG_PRINT(__pracro_class##cl, #ch, fmt)
+#define __PRACRO_DEBUG_VA(cl, ch, fmt, a)	__PRACRO_DEBUG_PRINT_VA(__pracro_class##cl, #ch, fmt, a)
+
+#define PRACRO_FIXME(ch, fmt...)	__PRACRO_DEBUG(_fixme, ch, fmt)
+#define PRACRO_INFO(ch, fmt...)		__PRACRO_DEBUG(_info, ch, fmt)
+#define PRACRO_WARN(ch, fmt...)		__PRACRO_DEBUG(_warn, ch, fmt)
+#define PRACRO_ERR(ch, fmt...)		__PRACRO_DEBUG(_err, ch, fmt)
+#define PRACRO_DEBUG(ch, fmt...)	__PRACRO_DEBUG(_debug, ch, fmt)
+#define PRACRO_FIXME_VA(ch, fmt, a)	__PRACRO_DEBUG_VA(_fixme, ch, fmt, a)
+#define PRACRO_INFO_VA(ch, fmt, a)	__PRACRO_DEBUG_VA(_info, ch, fmt, a)
+#define PRACRO_WARN_VA(ch, fmt, a)	__PRACRO_DEBUG_VA(_warn, ch, fmt, a)
+#define PRACRO_ERR_VA(ch, fmt, a)	__PRACRO_DEBUG_VA(_err, ch, fmt, a)
+#define PRACRO_DEBUG_VA(ch, fmt, a)	__PRACRO_DEBUG_VA(_debug, ch, fmt, a)
+
+#define PRACRO_INFO_LOG(ch, fmt...)	PRACRO_INFO(ch, fmt)
+#define PRACRO_WARN_LOG(ch, fmt...)	PRACRO_WARN(ch, fmt)
+#define PRACRO_ERR_LOG(ch, fmt...)	PRACRO_ERR(ch, fmt)
+#define PRACRO_INFO_LOG_VA(ch, fmt, a)	PRACRO_INFO_VA(ch, fmt, a)
+#define PRACRO_WARN_LOG_VA(ch, fmt, a)	PRACRO_WARN_VA(ch, fmt, a)
+#define PRACRO_ERR_LOG_VA(ch, fmt, a)	PRACRO_ERR_VA(ch, fmt, a)
+
+#else
+
+/* If we compile without debug support, we want them all to go away */
+#define PRACRO_FIXME(ch, fmt...)
+#define PRACRO_INFO(ch, fmt...)
+#define PRACRO_WARN(ch, fmt...)
+#define PRACRO_ERR(ch, fmt...)
+#define PRACRO_DEBUG(ch, fmt...)
+#define PRACRO_FIXME_VA(ch, fmt...)
+#define PRACRO_INFO_VA(ch, fmt...)
+#define PRACRO_WARN_VA(ch, fmt...)
+#define PRACRO_ERR_VA(ch, fmt...)
+#define PRACRO_DEBUG_VA(ch, fmt...)
+
+int __pracro_log(const char *func, const int line, enum __pracro_debug_class cl, const char *ch, const char *fmt, ...) __attribute__((format (printf,5,6)));
+int __pracro_log_va(const char *func, const int line, enum __pracro_debug_class cl, const char *ch, const char *fmt, va_list va);
+
+#define __PRACRO_LOG_PRINT(cl, ch, fmt...)	\
+	do { __pracro_log(__func__, __LINE__, cl, ch, fmt); } while(0)
+#define __PRACRO_LOG_PRINT_VA(cl, ch, fmt, a)	\
+	do { __pracro_log_va(__func__, __LINE__, cl, ch, fmt, a); } while(0)
+#define __PRACRO_LOG(cl, ch, fmt...)	__PRACRO_LOG_PRINT(__pracro_class##cl, #ch, fmt)
+#define __PRACRO_LOG_VA(cl, ch, fmt, a)	__PRACRO_LOG_PRINT_VA(__pracro_class##cl, #ch, fmt, a)
+
+#define PRACRO_INFO_LOG(ch, fmt...)	__PRACRO_LOG(_info, ch, fmt)
+#define PRACRO_WARN_LOG(ch, fmt...)	__PRACRO_LOG(_warn, ch, fmt)
+#define PRACRO_ERR_LOG(ch, fmt...)	__PRACRO_LOG(_err, ch, fmt)
+#define PRACRO_INFO_LOG_VA(ch, fmt, a)	__PRACRO_LOG_VA(ch, fmt, a)
+#define PRACRO_WARN_LOG_VA(ch, fmt, a)	__PRACRO_LOG_VA(ch, fmt, a)
+#define PRACRO_ERR_LOG_VA(ch, fmt, a)	__PRACRO_LOG_VA(ch, fmt, a)
+
+#endif/*WITH_DEBUG*/
+
 #endif/*__ARTEFACT_DEBUG_H__*/
diff --git a/server/src/macroparser.cc b/server/src/macroparser.cc
index ae7f648..c5b524d 100644
--- a/server/src/macroparser.cc
+++ b/server/src/macroparser.cc
@@ -24,6 +24,7 @@
  *  along with Pracro; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
+#include "debug.h"
 #include "macroparser.h"
 #include "configuration.h"
 
@@ -53,11 +54,11 @@ void MacroParser::error(const char* fmt, ...)
 {
   // TODO: Throw exception here.
 
-  fprintf(stderr, "Error in MacroParser: ");
+  PRACRO_ERR_LOG(macro, "Error in MacroParser: ");
 
   va_list argp;
   va_start(argp, fmt);
-  vfprintf(stderr, fmt, argp);
+  PRACRO_ERR_LOG_VA(macro, fmt, argp);
   va_end(argp);
 
   fprintf(stderr, "\n");
@@ -74,7 +75,7 @@ MacroParser::MacroParser(std::string macro)
 
   file = Conf::xml_basedir + "/macros/" + macro + ".xml";
 
-  printf("Using macro file: %s\n", file.c_str());
+  PRACRO_DEBUG(macro, "Using macro file: %s\n", file.c_str());
 
   fd = open(file.c_str(), O_RDONLY);
   if(fd == -1) error("Could not open file %s", file.c_str());
@@ -280,12 +281,12 @@ void MacroParser::endTag(std::string name)
 int MacroParser::readData(char *data, size_t size)
 {
   if(fd == -1) {
-    fprintf(stderr, "Invalid file descriptor.\n"); fflush(stderr);
+    PRACRO_ERR_LOG(macro, "Invalid file descriptor.\n");
     return 0;
   }
   ssize_t r = read(fd, data, size);
   if(r == -1) {
-    printf("Could not read...%s\n", strerror(errno)); fflush(stdout);
+    PRACRO_ERR_LOG(macro, "Could not read...%s\n", strerror(errno));
     return 0;
   }
   return r;
@@ -293,11 +294,10 @@ int MacroParser::readData(char *data, size_t size)
 
 void MacroParser::parseError(char *buf, size_t len, std::string error, int lineno)
 {
-  fprintf(stderr, "MacroParser[%s] error at line %d: %s\n", file.c_str(), lineno, error.c_str());
-  fprintf(stderr, "\tBuffer %u bytes: [", len);
+  PRACRO_ERR_LOG(macro, "MacroParser[%s] error at line %d: %s\n", file.c_str(), lineno, error.c_str());
+  PRACRO_ERR_LOG(macro, "\tBuffer %u bytes: [", len);
   if(fwrite(buf, len, 1, stderr) != len) {}
-  fprintf(stderr, "]\n");
-  fflush(stderr);
+  PRACRO_ERR_LOG(macro, "]\n");
 }
 
 Macro *MacroParser::getMacro()
diff --git a/server/src/pracrod.cc b/server/src/pracrod.cc
index 634ae67..a1c8ba1 100644
--- a/server/src/pracrod.cc
+++ b/server/src/pracrod.cc
@@ -62,6 +62,8 @@
 
 #include "tcpsocket.h"
 
+#include "debug.h"
+
 static const char version_str[] =
 "Pracro server v" VERSION "\n"
 ;
@@ -85,6 +87,7 @@ static const char usage_str[] =
 "  -x, --xml-basedir d Use 'd' as basedir for finding template- and macro-files (default "XML").\n"
 "  -v, --version       Print version information and exit.\n"
 "  -h, --help          Print this message and exit.\n"
+"  -D, --debug ddd     Enable debug messages on 'ddd'; see documentation for details\n"
 ;
 
 ConfigurationParser *configparser = NULL;
@@ -141,6 +144,9 @@ int main(int argc, char *argv[])
   char *group = NULL;
   bool foreground = false;
   char *xml_basedir = NULL;
+  char *debugstr = NULL;
+
+  pracro_debug_init();
 
   int option_index = 0;
   while(1) {
@@ -153,10 +159,11 @@ int main(int argc, char *argv[])
       {"help", no_argument, 0, 'h'},
       {"version", no_argument, 0, 'v'},
       {"xml-basedir", required_argument, 0, 'x'},
+      {"debug", required_argument, 0, 'D'},
       {0, 0, 0, 0}
     };
     
-    c = getopt_long (argc, argv, "hvfc:u:g:x:", long_options, &option_index);
+    c = getopt_long (argc, argv, "D:hvfc:u:g:x:", long_options, &option_index);
     
     if (c == -1)
       break;
@@ -182,6 +189,10 @@ int main(int argc, char *argv[])
       xml_basedir = strdup(optarg);
       break;
 
+    case 'D':
+      debugstr = strdup(optarg);
+      break;
+
     case '?':
     case 'h':
       printf(version_str);
@@ -198,6 +209,10 @@ int main(int argc, char *argv[])
     }
   }
 
+  if(debugstr) {
+    pracro_debug_parse(debugstr);
+  }
+
   // Load config
   if(configfile) configparser = new ConfigurationParser(configfile);
   else configparser = new ConfigurationParser(ETC"/pracrod.conf");
diff --git a/server/src/queryhandler.cc b/server/src/queryhandler.cc
index a6b6e1b..7077ab8 100644
--- a/server/src/queryhandler.cc
+++ b/server/src/queryhandler.cc
@@ -24,6 +24,8 @@
  *  along with Pracro; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
+#include "debug.h"
+
 #include "queryhandler.h"
 
 #include <config.h>
@@ -156,9 +158,7 @@ QueryResult QueryHandler::exec(Query &query)
   socket->write(header, strlen(header));
 #endif/*WITHOUT_PENTOMINOS*/
 
-#ifdef WITH_DEBUG
-  printf(header);
-#endif/*WITH_DEBUG*/
+  PRACRO_DEBUG(pentominos, header);
 
   sprintf(buf, "  <pentominos:entry cpr=\"%s\"\n"
           "                    src_addr=\"%s\"\n"
@@ -179,9 +179,7 @@ QueryResult QueryHandler::exec(Query &query)
   socket->write(buf, strlen(buf));
 #endif/*WITHOUT_PENTOMINOS*/
 
-#ifdef WITH_DEBUG
-  printf(buf);
-#endif/*WITH_DEBUG*/
+  PRACRO_DEBUG(pentominos, buf);
 
   sprintf(buf, "  <pentominos:query format=\"pracroxml\"\n"
           "                    device_id=\"%s\"\n"
@@ -195,9 +193,7 @@ QueryResult QueryHandler::exec(Query &query)
   socket->write(buf, strlen(buf));
 #endif/*WITHOUT_PENTOMINOS*/
 
-#ifdef WITH_DEBUG
-  printf(buf);
-#endif/*WITH_DEBUG*/
+  PRACRO_DEBUG(pentominos, buf);
 
   sprintf(buf, "</artefact>");
 
@@ -205,10 +201,7 @@ QueryResult QueryHandler::exec(Query &query)
   socket->write(buf, strlen(buf));
 #endif/*WITHOUT_PENTOMINOS*/
 
-#ifdef WITH_DEBUG
-  printf(buf);
-  fflush(stdout);
-#endif/*WITH_DEBUG*/
+  PRACRO_DEBUG(pentominos, buf);
 
   QueryResult result;
 
@@ -226,7 +219,7 @@ QueryResult QueryHandler::exec(Query &query)
   result = parser.result;
 #endif/*WITHOUT_PENTOMINOS*/
 
-  printf("Done handling query\n");
+  PRACRO_DEBUG(pentominos, "Done handling query\n");
 
   return result;
 }
diff --git a/server/src/tcpsocket.cc b/server/src/tcpsocket.cc
index 9d481ff..f72d7b6 100644
--- a/server/src/tcpsocket.cc
+++ b/server/src/tcpsocket.cc
@@ -24,10 +24,11 @@
  *  along with Artefact; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
+#include <config.h>
+
 #include "tcpsocket.h"
 
 #include "debug.h"
-#include <config.h>
 
 //#define WITH_DEBUG
 
@@ -89,16 +90,12 @@ TCPSocket::TCPSocket(std::string name, int sock)
   isconnected = false;
   this->sock = sock;
 
-#ifdef WITH_DEBUG
-   printf("TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
-#endif/*WITH_DEBUG*/
+  PRACRO_DEBUG(socket, "TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
 }
 
 TCPSocket::~TCPSocket()
 {
-#ifdef WITH_DEBUG
-  printf("~TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
-#endif/*WITH_DEBUG*/
+  PRACRO_DEBUG(socket, "~TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
   disconnect();
 }
 
@@ -155,7 +152,7 @@ TCPSocket *TCPSocket::accept()
   FD_SET(sock, &fset);
   if( (ret = select (sock+1, &fset, NULL, NULL, NULL)) < 0) { 
     if(errno == EINTR) {
-      printf("Accept got interrupt!\n");
+      PRACRO_DEBUG(socket, "Accept got interrupt!\n");
       return NULL; // a signal caused select to return. That is OK with me
     } else {
       throw TCPAcceptException("Select on socket failed.");
@@ -171,7 +168,7 @@ TCPSocket *TCPSocket::accept()
     child->isconnected = true;
     return child;
   } else {
-    printf("Accept returned with no socket - This should not happen!\n");
+    PRACRO_ERR_LOG(socket, "Accept returned with no socket - This should not happen!\n");
     return NULL;
   }
 }
@@ -222,9 +219,7 @@ void TCPSocket::connect(std::string addr, unsigned short int port)
 void TCPSocket::disconnect()
 {
   if(sock != -1) {
-#ifdef WITH_DEBUG
-    printf("Closing TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
-#endif/*WITH_DEBUG*/
+    PRACRO_DEBUG(socket, "Closing TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
     int ret = close(sock);
     if(ret == -1) {
       perror(name.c_str());
@@ -274,7 +269,7 @@ int TCPSocket::read(char *buf, int size, long timeout)
   switch(ret) {
   case -1:
     if(errno == EINTR) {
-      printf("EINTR - got interrupt\n");
+      PRACRO_DEBUG(socket, "EINTR - got interrupt\n");
       return -1; // a signal caused select to return. That is OK with me
     } else {
       throw TCPReadException("Select on socket (read) failed.");
@@ -283,7 +278,7 @@ int TCPSocket::read(char *buf, int size, long timeout)
 
   case 0:
     // timeout
-    printf("Timeout\n");
+    PRACRO_DEBUG(socket, "Timeout\n");
     break;
 
   default:
@@ -293,7 +288,7 @@ int TCPSocket::read(char *buf, int size, long timeout)
         throw TCPReadException(strerror(errno));
       }
     } else {
-      printf("FD_ISSET failed (timeout?)\n");
+      PRACRO_DEBUG(socket, "FD_ISSET failed (timeout?)\n");
       return 0;
     }
   }
diff --git a/server/src/widgetgenerator.cc b/server/src/widgetgenerator.cc
index 58f2992..2e51b32 100644
--- a/server/src/widgetgenerator.cc
+++ b/server/src/widgetgenerator.cc
@@ -24,6 +24,7 @@
  *  along with Pracro; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
+#include "debug.h"
 #include "widgetgenerator.h"
 
 #include "configuration.h"
@@ -54,7 +55,7 @@ static std::string automap(std::string name)
     "end\n"
     "return value, timestamp\n";
 
-  printf("Automap:\n%s\n", automapstring.c_str());
+  PRACRO_DEBUG(widget, "Automap:\n%s\n", automapstring.c_str());
 
   return automapstring;
 }
-- 
cgit v1.2.3