Index: libfdproto/dictionary.c
===================================================================
--- libfdproto/dictionary.c	(revision 662)
+++ libfdproto/dictionary.c	(revision 687)
@@ -1304,48 +1304,48 @@
 
 /* Default dump functions */
-static void dump_val_os(union avp_value * value)
+static void dump_val_os(union avp_value * value, FILE * fstr)
 {
 	int i;
 	for (i = 0; i < value->os.len; i++) {
 		if (i == 24) { /* Dump only up to 24 bytes of the buffer */
-			fd_log_debug("[...] (len=%zd)", value->os.len);
+			fd_log_debug_fstr(fstr, "[...] (len=%zd)", value->os.len);
 			break;
 		}
-		fd_log_debug("%02.2X ", value->os.data[i]);
-	}
-}
-
-static void dump_val_i32(union avp_value * value)
-{
-	fd_log_debug("%i (0x%x)", value->i32, value->i32);
-}
-
-static void dump_val_i64(union avp_value * value)
-{
-	fd_log_debug("%lli (0x%llx)", value->i64, value->i64);
-}
-
-static void dump_val_u32(union avp_value * value)
-{
-	fd_log_debug("%u (0x%x)", value->u32, value->u32);
-}
-
-static void dump_val_u64(union avp_value * value)
-{
-	fd_log_debug("%llu (0x%llx)", value->u64, value->u64);
-}
-
-static void dump_val_f32(union avp_value * value)
-{
-	fd_log_debug("%f", value->f32);
-}
-
-static void dump_val_f64(union avp_value * value)
-{
-	fd_log_debug("%g", value->f64);
+		fd_log_debug_fstr(fstr, "%02.2X ", value->os.data[i]);
+	}
+}
+
+static void dump_val_i32(union avp_value * value, FILE * fstr)
+{
+	fd_log_debug_fstr(fstr, "%i (0x%x)", value->i32, value->i32);
+}
+
+static void dump_val_i64(union avp_value * value, FILE * fstr)
+{
+	fd_log_debug_fstr(fstr, "%lli (0x%llx)", value->i64, value->i64);
+}
+
+static void dump_val_u32(union avp_value * value, FILE * fstr)
+{
+	fd_log_debug_fstr(fstr, "%u (0x%x)", value->u32, value->u32);
+}
+
+static void dump_val_u64(union avp_value * value, FILE * fstr)
+{
+	fd_log_debug_fstr(fstr, "%llu (0x%llx)", value->u64, value->u64);
+}
+
+static void dump_val_f32(union avp_value * value, FILE * fstr)
+{
+	fd_log_debug_fstr(fstr, "%f", value->f32);
+}
+
+static void dump_val_f64(union avp_value * value, FILE * fstr)
+{
+	fd_log_debug_fstr(fstr, "%g", value->f64);
 }
 
 /* Get the dump function for basic dict_avp_basetype */
-static void (*get_default_dump_val_cb(enum dict_avp_basetype datatype))(union avp_value *)
+static void (*get_default_dump_val_cb(enum dict_avp_basetype datatype))(union avp_value *, FILE *)
 {
 	switch (datatype) {
@@ -1382,32 +1382,32 @@
 
 /* Formater for the AVP value dump line */
-static void dump_avp_val(union avp_value *avp_value, void (*dump_val_cb)(union avp_value *avp_value), enum dict_avp_basetype datatype, char * type_name, char * const_name, int indent)
+static void dump_avp_val(union avp_value *avp_value, void (*dump_val_cb)(union avp_value *, FILE *), enum dict_avp_basetype datatype, char * type_name, char * const_name, int indent, FILE * fstr)
 {
 	/* Header for all AVP values dumps: */
-	fd_log_debug(INOBJHDR "value ", INOBJHDRVAL);
+	fd_log_debug_fstr(fstr, INOBJHDR "value ", INOBJHDRVAL);
 	
 	/* If the type is provided, write it */
 	if (type_name)
-		fd_log_debug("t: '%s' ", type_name);
+		fd_log_debug_fstr(fstr, "t: '%s' ", type_name);
 	
 	/* Always give the base datatype anyway */
-	fd_log_debug("(%s) ", type_base_name[datatype]);
+	fd_log_debug_fstr(fstr, "(%s) ", type_base_name[datatype]);
 	
 	/* Now, the value */
-	fd_log_debug("v: ");
+	fd_log_debug_fstr(fstr, "v: ");
 	if (const_name)
-		fd_log_debug("'%s' (", const_name);
-	(*dump_val_cb)(avp_value);
+		fd_log_debug_fstr(fstr, "'%s' (", const_name);
+	(*dump_val_cb)(avp_value, fstr);
 	if (const_name)
-		fd_log_debug(")");
+		fd_log_debug_fstr(fstr, ")");
 	
 	/* Done! */
-	fd_log_debug("\n");
+	fd_log_debug_fstr(fstr, "\n");
 }
 
 /* Dump the value of an AVP of known type */
-void fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent)
-{
-	void (*dump_val_cb)(union avp_value *avp_value);
+void fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, FILE * fstr)
+{
+	void (*dump_val_cb)(union avp_value *avp_value, FILE * fstr);
 	struct dict_object * type = NULL;
 	char * type_name = NULL;
@@ -1444,5 +1444,5 @@
 	
 	/* And finally, dump the value */
-	dump_avp_val(avp_value, dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent);
+	dump_avp_val(avp_value, dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, fstr);
 }
 
Index: libfdproto/fdproto-internal.h
===================================================================
--- libfdproto/fdproto-internal.h	(revision 662)
+++ libfdproto/fdproto-internal.h	(revision 687)
@@ -48,4 +48,7 @@
 void fd_sess_fini(void);
 
+/* Where debug messages are sent */
+FILE * fd_g_debug_fstr;
+
 /* Iterator on the rules of a parent object */
 int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) );
@@ -53,5 +56,5 @@
 /* Dispatch / messages / dictionary API */
 int fd_dict_disp_cb(enum dict_object_type type, struct dict_object *obj, struct fd_list ** cb_list);
-void fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent);
+void fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, FILE * fstr);
 int fd_disp_call_cb_int( struct fd_list * cb_list, struct msg ** msg, struct avp *avp, struct session *sess, enum disp_action *action, 
 			struct dict_object * obj_app, struct dict_object * obj_cmd, struct dict_object * obj_avp, struct dict_object * obj_enu);
Index: libfdproto/init.c
===================================================================
--- libfdproto/init.c	(revision 662)
+++ libfdproto/init.c	(revision 687)
@@ -51,4 +51,7 @@
 	}
 	
+	/* Set the debug stream */
+	fd_g_debug_fstr = stdout;
+	
 	/* Initialize the modules that need it */
 	fd_msg_eteid_init();
Index: libfdproto/log.c
===================================================================
--- libfdproto/log.c	(revision 662)
+++ libfdproto/log.c	(revision 687)
@@ -55,7 +55,6 @@
 }
 
-
 /* Log a debug message */
-void fd_log_debug ( const char * format, ... )
+void fd_log_debug_fstr ( FILE * fstr, const char * format, ... )
 {
 	va_list ap;
@@ -66,7 +65,7 @@
 	
 	va_start(ap, format);
-	vfprintf( stdout, format, ap);
+	vfprintf( fstr ?: stdout, format, ap);
 	va_end(ap);
-	fflush(stdout);
+	fflush(fstr ?: stdout);
 
 	pthread_cleanup_pop(0);
Index: libfdproto/messages.c
===================================================================
--- libfdproto/messages.c	(revision 686)
+++ libfdproto/messages.c	(revision 687)
@@ -661,12 +661,12 @@
 
 /* Dump a msg_t object */
-static void obj_dump_msg (struct msg * msg, int indent )
+static void obj_dump_msg (struct msg * msg, int indent, FILE * fstr )
 {
 	int ret = 0;
 	
-	fd_log_debug("%*sMSG: %p\n", INOBJHDRVAL, msg);
+	fd_log_debug_fstr(fstr, "%*sMSG: %p\n", INOBJHDRVAL, msg);
 	
 	if (!CHECK_MSG(msg)) {
-		fd_log_debug(INOBJHDR "INVALID!\n", INOBJHDRVAL);
+		fd_log_debug_fstr(fstr, INOBJHDR "INVALID!\n", INOBJHDRVAL);
 		return;
 	}
@@ -674,5 +674,5 @@
 	if (!msg->msg_model) {
 		
-		fd_log_debug(INOBJHDR "(no model)\n", INOBJHDRVAL);
+		fd_log_debug_fstr(fstr, INOBJHDR "(no model)\n", INOBJHDRVAL);
 		
 	} else {
@@ -682,17 +682,17 @@
 		ret = fd_dict_gettype(msg->msg_model, &dicttype);
 		if (ret || (dicttype != DICT_COMMAND)) {
-			fd_log_debug(INOBJHDR "(invalid model: %d %d)\n", INOBJHDRVAL, ret, dicttype);
+			fd_log_debug_fstr(fstr, INOBJHDR "(invalid model: %d %d)\n", INOBJHDRVAL, ret, dicttype);
 			goto public;
 		}
 		ret = fd_dict_getval(msg->msg_model, &dictdata);
 		if (ret != 0) {
-			fd_log_debug(INOBJHDR "(error getting model data: %s)\n", INOBJHDRVAL, strerror(ret));
+			fd_log_debug_fstr(fstr, INOBJHDR "(error getting model data: %s)\n", INOBJHDRVAL, strerror(ret));
 			goto public;
 		}
-		fd_log_debug(INOBJHDR "model : v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %u \"%s\"\n", INOBJHDRVAL, 
+		fd_log_debug_fstr(fstr, INOBJHDR "model : v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %u \"%s\"\n", INOBJHDRVAL, 
 			DUMP_CMDFL_val(dictdata.cmd_flag_val), DUMP_CMDFL_val(dictdata.cmd_flag_mask), dictdata.cmd_code, dictdata.cmd_name);
 	}
 public:	
-	fd_log_debug(INOBJHDR "public: V:%d L:%d fl:" DUMP_CMDFL_str " CC:%u A:%d hi:%x ei:%x\n", INOBJHDRVAL, 
+	fd_log_debug_fstr(fstr, INOBJHDR "public: V:%d L:%d fl:" DUMP_CMDFL_str " CC:%u A:%d hi:%x ei:%x\n", INOBJHDRVAL, 
 		msg->msg_public.msg_version,
 		msg->msg_public.msg_length,
@@ -703,10 +703,10 @@
 		msg->msg_public.msg_eteid
 		);
-	fd_log_debug(INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p asso:%d sess:%p src:%s\n", 
+	fd_log_debug_fstr(fstr, INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p asso:%d sess:%p src:%s\n", 
 			INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_associated, msg->msg_sess, msg->msg_src_id?:"(nil)");
 }
 
 /* Dump an avp object */
-static void obj_dump_avp ( struct avp * avp, int indent )
+static void obj_dump_avp ( struct avp * avp, int indent, FILE * fstr )
 {
 	int ret = 0;
@@ -714,5 +714,5 @@
 	
 	if (!CHECK_AVP(avp)) {
-		fd_log_debug(INOBJHDR "INVALID!\n", INOBJHDRVAL);
+		fd_log_debug_fstr(fstr, INOBJHDR "INVALID!\n", INOBJHDRVAL);
 		return;
 	}
@@ -720,5 +720,5 @@
 	if (!avp->avp_model) {
 		
-		fd_log_debug(INOBJHDR "(no model)\n", INOBJHDRVAL);
+		fd_log_debug_fstr(fstr, INOBJHDR "(no model)\n", INOBJHDRVAL);
 		
 	} else {
@@ -728,13 +728,13 @@
 		ret = fd_dict_gettype(avp->avp_model, &dicttype);
 		if (ret || (dicttype != DICT_AVP)) {
-			fd_log_debug(INOBJHDR "(invalid model: %d %d)\n", INOBJHDRVAL, ret, dicttype);
+			fd_log_debug_fstr(fstr, INOBJHDR "(invalid model: %d %d)\n", INOBJHDRVAL, ret, dicttype);
 			goto public;
 		}
 		ret = fd_dict_getval(avp->avp_model, &dictdata);
 		if (ret != 0) {
-			fd_log_debug(INOBJHDR "(error getting model data: %s)\n", INOBJHDRVAL, strerror(ret));
+			fd_log_debug_fstr(fstr, INOBJHDR "(error getting model data: %s)\n", INOBJHDRVAL, strerror(ret));
 			goto public;
 		}
-		fd_log_debug(INOBJHDR "model : v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %u \"%s\"\n", INOBJHDRVAL, 
+		fd_log_debug_fstr(fstr, INOBJHDR "model : v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %u \"%s\"\n", INOBJHDRVAL, 
 			DUMP_AVPFL_val(dictdata.avp_flag_val), 
 			DUMP_AVPFL_val(dictdata.avp_flag_mask), 
@@ -745,5 +745,5 @@
 	}
 public:	
-	fd_log_debug(INOBJHDR "public: C:%u fl:" DUMP_AVPFL_str " L:%d V:%u  data:@%p\n", INOBJHDRVAL, 
+	fd_log_debug_fstr(fstr, INOBJHDR "public: C:%u fl:" DUMP_AVPFL_str " L:%d V:%u  data:@%p\n", INOBJHDRVAL, 
 		avp->avp_public.avp_code,
 		DUMP_AVPFL_val(avp->avp_public.avp_flags),
@@ -755,15 +755,15 @@
 	if (avp->avp_public.avp_value) {
 		if (!avp->avp_model) {
-			fd_log_debug(INOBJHDR "(data set but no model: ERROR)\n", INOBJHDRVAL);
+			fd_log_debug_fstr(fstr, INOBJHDR "(data set but no model: ERROR)\n", INOBJHDRVAL);
 		} else {
-			fd_dict_dump_avp_value(avp->avp_public.avp_value, avp->avp_model, indent);
-		}
-	}
-
-	fd_log_debug(INOBJHDR "intern: src:%p mf:%d raw:%p(%d)\n", INOBJHDRVAL, avp->avp_source, avp->avp_mustfreeos, avp->avp_rawdata, avp->avp_rawlen);
+			fd_dict_dump_avp_value(avp->avp_public.avp_value, avp->avp_model, indent, fstr);
+		}
+	}
+
+	fd_log_debug_fstr(fstr, INOBJHDR "intern: src:%p mf:%d raw:%p(%d)\n", INOBJHDRVAL, avp->avp_source, avp->avp_mustfreeos, avp->avp_rawdata, avp->avp_rawlen);
 }
 
 /* Dump a single object content */
-static void msg_dump_intern ( int level, msg_or_avp * obj, int indent )
+static void msg_dump_intern ( int level, msg_or_avp * obj, int indent, FILE * fstr )
 {
 	/* Log only if we are at least at level */
@@ -773,5 +773,5 @@
 	/* Check the object */
 	if (!VALIDATE_OBJ(obj)) {
-		fd_log_debug( ">>> invalid object (%p)!.\n", obj);
+		fd_log_debug_fstr(fstr, ">>> invalid object (%p)!.\n", obj);
 		return;
 	}
@@ -780,9 +780,9 @@
 	switch (_C(obj)->type) {
 		case MSG_AVP:
-			obj_dump_avp ( _A(obj), indent );
+			obj_dump_avp ( _A(obj), indent, fstr );
 			break;
 		
 		case MSG_MSG:
-			obj_dump_msg ( _M(obj), indent );
+			obj_dump_msg ( _M(obj), indent, fstr );
 			break;
 		
@@ -792,4 +792,19 @@
 }
 
+/* Dump a message to a specified file stream */
+static void fd_msg_dump_fstr ( struct msg * msg, FILE * fstr )
+{
+	msg_or_avp * ref = msg;
+	int indent = 2;
+	do {
+		msg_dump_intern ( NONE, ref, indent, fstr );
+		
+		/* Now find the next object */
+		CHECK_FCT_DO(  fd_msg_browse ( ref, MSG_BRW_WALK, &ref, &indent ), break  );
+		
+		/* dump next object */
+	} while (ref);
+}
+
 /* Dump a message content -- for debug mostly */
 void fd_msg_dump_walk ( int level, msg_or_avp *obj )
@@ -800,5 +815,5 @@
 	TRACE_DEBUG(level, "------ Dumping object %p (w)-------", obj);
 	do {
-		msg_dump_intern ( level, ref, indent );
+		msg_dump_intern ( level, ref, indent, fd_g_debug_fstr );
 		
 		/* Now find the next object */
@@ -815,5 +830,5 @@
 {
 	TRACE_DEBUG(level, "------ Dumping object %p (s)-------", obj);
-	msg_dump_intern ( level, obj, 1 );
+	msg_dump_intern ( level, obj, 1, fd_g_debug_fstr );
 	TRACE_DEBUG(level, "------ /end of object %p -------", obj);
 }
@@ -1645,5 +1660,5 @@
 		if (mandatory && (avp->avp_public.avp_flags & AVP_FLAG_MANDATORY)) {
 			TRACE_DEBUG(INFO, "Unsupported mandatory AVP found:");
-			msg_dump_intern(INFO, avp, 2);
+			msg_dump_intern(INFO, avp, 2, fd_g_debug_fstr);
 			if (error_info) {
 				error_info->pei_errcode = "DIAMETER_AVP_UNSUPPORTED";
@@ -2309,2 +2324,122 @@
 	return ret;
 }
+
+
+/***************************************************************************************************************/
+/* messages logging facility */
+#include <stdarg.h>
+
+static struct {
+	struct {
+		enum fd_msg_log_method 	meth;
+		const char * 		metharg;
+	} causes[FD_MSG_LOG_MAX + 1];
+	pthread_mutex_t lock;
+	int		init;
+} ml_conf = { .lock = PTHREAD_MUTEX_INITIALIZER, .init = 0 };
+
+static void ml_conf_init(void) 
+{
+	memset(&ml_conf.causes, 0, sizeof(ml_conf.causes));
+	ml_conf.init = 1;
+}
+
+/* Set a configuration property */
+int fd_msg_log_config(enum fd_msg_log_cause cause, enum fd_msg_log_method method, const char * arg)
+{
+	/* Check the parameters are valid */
+	TRACE_ENTRY("%d %d %p", cause, method, arg);
+	CHECK_PARAMS( (cause >= 0) && (cause <= FD_MSG_LOG_MAX) );
+	CHECK_PARAMS( (method >= FD_MSG_LOGTO_DEBUGONLY) && (method <= FD_MSG_LOGTO_DIR) );
+	CHECK_PARAMS( (method == FD_MSG_LOGTO_DEBUGONLY) || (arg != NULL) );
+	
+	/* Lock the configuration */
+	CHECK_POSIX( pthread_mutex_lock(&ml_conf.lock) );
+	if (!ml_conf.init) {
+		ml_conf_init();
+	}
+	
+	/* Now set the parameter */
+	ml_conf.causes[cause].meth = method;
+	ml_conf.causes[cause].metharg = arg;
+	
+	if (method) {
+		TRACE_DEBUG(INFO, "Logging %s messages set to %s '%s'", 
+			(cause == FD_MSG_LOG_DROPPED) ? "DROPPED" :
+				(cause == FD_MSG_LOG_RECEIVED) ? "RECEIVED" :
+					(cause == FD_MSG_LOG_SENT) ? "SENT" :
+						"???",
+			(method == FD_MSG_LOGTO_FILE) ? "file" :
+				(method == FD_MSG_LOGTO_DIR) ? "directory" :
+					"???",
+			arg);
+	}
+	
+	CHECK_POSIX( pthread_mutex_unlock(&ml_conf.lock) );
+	
+	/* Done */
+	return 0;
+}
+
+/* Do not log anything within this one, since log lock is held */
+static void fd_cleanup_mutex_silent( void * mutex )
+{
+	(void)pthread_mutex_unlock((pthread_mutex_t *)mutex);
+}
+
+/* Really log the message */
+void fd_msg_log( enum fd_msg_log_cause cause, struct msg * msg, const char * prefix_format, ... )
+{
+	va_list ap;
+	enum fd_msg_log_method 	meth;
+	const char * 		metharg;
+	FILE * fstr;
+	
+	TRACE_ENTRY("%d %p %p", cause, msg, prefix_format);
+	CHECK_PARAMS_DO( (cause >= 0) && (cause <= FD_MSG_LOG_MAX),
+	{
+		TRACE_DEBUG(INFO, "Invalid cause received (%d)! Message was:", cause);
+		fd_msg_dump_walk(INFO, msg);
+	} );
+	
+	/* First retrieve the config for this message */
+	CHECK_POSIX_DO( pthread_mutex_lock(&ml_conf.lock), );
+	if (!ml_conf.init) {
+		ml_conf_init();
+	}
+	meth    = ml_conf.causes[cause].meth;
+	metharg = ml_conf.causes[cause].metharg;
+	CHECK_POSIX_DO( pthread_mutex_unlock(&ml_conf.lock), );
+	
+	/* Okay, now we will create the file descriptor */
+	switch (meth) {
+		case FD_MSG_LOGTO_DEBUGONLY:
+			fstr = fd_g_debug_fstr;
+			break;
+			
+		case FD_MSG_LOGTO_FILE:
+			TODO("Log to arg file");
+			break;
+		case FD_MSG_LOGTO_DIR:
+			TODO("Log to arg directory in a new file");
+			break;
+	}
+	
+	/* Then dump the prefix message to this stream */
+	(void)pthread_mutex_lock(&fd_log_lock);
+	pthread_cleanup_push(fd_cleanup_mutex_silent, &fd_log_lock);
+	va_start(ap, prefix_format);
+	vfprintf( fstr, prefix_format, ap);
+	va_end(ap);
+	fflush(fstr);
+	pthread_cleanup_pop(0);
+	(void)pthread_mutex_unlock(&fd_log_lock);
+	fd_log_debug_fstr(fstr, "\n\n");
+	
+	/* And now the message itself */
+	fd_msg_dump_fstr(msg, fstr);
+	
+	/* And finally close the stream if needed */
+	TODO("close?");
+}
+
