diff --git a/src/lib/include/fwts_log.h b/src/lib/include/fwts_log.h
index a659baa..513bf88 100644
--- a/src/lib/include/fwts_log.h
+++ b/src/lib/include/fwts_log.h
@@ -23,7 +23,10 @@
 #include <stdio.h>
 #include <stdarg.h>
 
-#define LOG_MAGIC	0xfe23ab13
+#include "fwts_list.h"
+
+#define LOG_MAGIC		(0xfe23ab13)
+#define LOG_MAX_BUF_SIZE	(4096)		/* Max output per log line */
 
 typedef enum {
 	LOG_RESULT	    = 0x00000001,
@@ -58,31 +61,56 @@ typedef enum {
 	LOG_LEVEL_INFO      = 0x00000010,
 } fwts_log_level;
 
+/*
+ *  different types of log file
+ */
 typedef enum {
 	LOG_TYPE_NONE       = 0x00000000,
 	LOG_TYPE_PLAINTEXT  = 0x00000001,
 	LOG_TYPE_JSON       = 0x00000002,
-	LOG_TYPE_XML        = 0x00000003,
-	LOG_TYPE_HTML       = 0x00000004,
+	LOG_TYPE_XML        = 0x00000004,
+	LOG_TYPE_HTML       = 0x00000008,
 } fwts_log_type;
 
+/*
+ *   different types of output log
+ */
+typedef enum {
+	LOG_FILENAME_TYPE_STDOUT = 0x00000001,	/* log output to stdout */
+	LOG_FILENAME_TYPE_STDERR = 0x00000002,	/* log output to stderr */
+	LOG_FILENAME_TYPE_FILE   = 0x00000003,	/* log output to a file */
+} fwts_log_filename_type;
+
+/*
+ *  top level log descriptor
+ */
 typedef struct log_t {
-	unsigned int magic;
-	FILE *fp;
-	char *owner;
-	int line_width;
-	int line_number;
-	struct fwts_log_ops_t *ops;
+	unsigned int magic;			/* magic ID of the log */
+	fwts_list log_files;			/* list of fwts_log_file */
+	int line_number;			/* keeps track of the line numbering */
+	char *owner;				/* who is writing to this log */
 } fwts_log;
 
+/*
+ *  info for a specific log type
+ */
+typedef struct {
+	FILE *fp;				/* file descriptor for log */
+	fwts_log *log;				/* parent log struct */
+	fwts_log_type type;			/* log type */
+	fwts_log_filename_type filename_type;	/* log filename type */
+	struct fwts_log_ops_t *ops;		/* log operators */
+	int line_width;				/* width of log in chars */
+} fwts_log_file;
+
 typedef struct fwts_log_ops_t {
-	int (*vprintf)(fwts_log *log, const fwts_log_field field, const fwts_log_level level, const char *status, const char *label, const char *prefix, const char *fmt, va_list args);
-	void (*underline)(fwts_log *log, int ch);
-	void (*newline)(fwts_log *log);
-	void (*section_begin)(fwts_log *, const char *tag);
-	void (*section_end)(fwts_log *);
-	void (*open)(fwts_log *);
-	void (*close)(fwts_log *);
+	int (*print)(fwts_log_file *log_file, const fwts_log_field field, const fwts_log_level level, const char *status, const char *label, const char *prefix, const char *buffer);
+	void (*underline)(fwts_log_file *log_file, int ch);
+	void (*newline)(fwts_log_file *log_file);
+	void (*section_begin)(fwts_log_file *log_file, const char *tag);
+	void (*section_end)(fwts_log_file *log_file);
+	void (*open)(fwts_log_file *log_file);
+	void (*close)(fwts_log_file *log_file);
 } fwts_log_ops;
 
 extern fwts_log_ops fwts_log_plaintext_ops;
@@ -116,6 +144,12 @@ int 	  fwts_log_line_number(fwts_log *log);
 void	  fwts_log_set_line_width(const int width);
 void	  fwts_log_section_begin(fwts_log *log, const char *name);
 void	  fwts_log_section_end(fwts_log *log);
+fwts_log_filename_type fwts_log_get_filename_type(const char *name);
+
+static inline int fwts_log_type_count(fwts_log_type type)
+{
+	return __builtin_popcount(type);
+}
 
 #define fwts_log_result(fw, fmt, args...)	\
 	fwts_log_printf(fw->results, LOG_RESULT, LOG_LEVEL_NONE, "", "", "", fmt, ## args)
diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c
index f808d8e..a6c2ba2 100644
--- a/src/lib/src/fwts_framework.c
+++ b/src/lib/src/fwts_framework.c
@@ -28,7 +28,8 @@
 
 #include "fwts.h"
 
-#define RESULTS_LOG	"results.log"
+/* Suffix ".log", ".xml", etc gets automatically appended */
+#define RESULTS_LOG	"results"
 
 #define FWTS_RUN_ALL_FLAGS		\
 	(FWTS_BATCH |			\
@@ -96,34 +97,6 @@ static const char *fwts_copyright[] = {
 };
 
 /*
- *  fwts_framework_log_suffix()
- *	set the log name suffix
- */
-static void fwts_framework_log_suffix(fwts_framework *fw, const char *suffix)
-{
-	char *ptr;
-	char *new;
-	size_t len;
-
-	/* Locate old suffix and kill it */
-	ptr = rindex(fw->results_logname, '.');
-	if (ptr != NULL)
-		*ptr = '\0';
-
-	/* Space for old log name sans old suffix + new suffix + '.' + '\0' */
-	len = strlen(fw->results_logname) + strlen(suffix) + 2;
-
-	if ((new = calloc(len, 1)) == NULL) {
-		fprintf(stderr, "Cannot allocate log name.\n");
-		exit(EXIT_FAILURE);
-	}
-
-	snprintf(new, len, "%s.%s", fw->results_logname, suffix);
-	free(fw->results_logname);
-	fw->results_logname = new;
-}
-
-/*
  *  fwts_framework_compare_priority()
  *	used to register tests sorted on run priority
  */
@@ -677,7 +650,7 @@ static fwts_framework_test *fwts_framework_test_find(fwts_framework *fw, const c
  *  fwts_framework_log()
  *	log a test result
  */
-void fwts_framework_log(fwts_framework *fw, 
+void fwts_framework_log(fwts_framework *fw,
 	fwts_log_field field,
 	const char *label,
 	fwts_log_level level,
@@ -860,6 +833,39 @@ static int fwts_framework_skip_test_parse(fwts_framework *fw, const char *arg, f
 	return FWTS_OK;
 }
 
+/*
+ *  fwts_framework_log_type_parse()
+ *	parse optarg of comma separated log types
+ */
+static int fwts_framework_log_type_parse(fwts_framework *fw, const char *arg)
+{
+	char *str;
+	char *token;
+	char *saveptr = NULL;
+
+	fw->log_type = 0;
+
+	for (str = (char*)arg; (token = strtok_r(str, ",", &saveptr)) != NULL; str = NULL) {
+		if (!strcmp(token, "plaintext"))
+			fw->log_type |= LOG_TYPE_PLAINTEXT;
+		else if (!strcmp(token, "json"))
+			fw->log_type |= LOG_TYPE_JSON;
+		else if (!strcmp(token, "xml"))
+			fw->log_type |= LOG_TYPE_XML;
+		else if (!strcmp(token, "html"))
+			fw->log_type |= LOG_TYPE_HTML;
+		else {
+			fprintf(stderr, "--log-type can be plaintext, xml, html or json.\n");
+			return FWTS_ERROR;
+		}
+	}
+
+	if (!fw->log_type)
+		fw->log_type = LOG_TYPE_PLAINTEXT;
+
+	return FWTS_OK;
+}
+
 int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const argv[], int option_char, int long_index)
 {
 	switch (option_char) {
@@ -975,22 +981,8 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
 			fwts_iasl_disassemble_all_to_file(fw);
 			return FWTS_COMPLETE;
 		case 32: /* --log-type */
-			if (!strcmp(optarg, "plaintext")) {
-				fw->log_type = LOG_TYPE_PLAINTEXT;
-				fwts_framework_log_suffix(fw, "log");
-			} else if (!strcmp(optarg, "json")) {
-				fw->log_type = LOG_TYPE_JSON;
-				fwts_framework_log_suffix(fw, "json");
-			} else if (!strcmp(optarg, "xml")) {
-				fw->log_type = LOG_TYPE_XML;
-				fwts_framework_log_suffix(fw, "xml");
-			} else if (!strcmp(optarg, "html")) {
-				fw->log_type = LOG_TYPE_HTML;
-				fwts_framework_log_suffix(fw, "html");
-			} else {
-				fprintf(stderr, "--log-type can be either plaintext, xml, html or json.\n");
-				return FWTS_ERROR;
-			}
+			fwts_framework_log_type_parse(fw, optarg);
+			/* FIX ME - check return */
 			break;
 		}
 		break;
@@ -1136,6 +1128,16 @@ int fwts_framework_args(const int argc, char **argv)
 		goto tidy_close;
 	}
 
+	/* Ensure we have just one log type specified for non-filename logging */
+	if (fwts_log_type_count(fw->log_type) > 1 &&
+	    fwts_log_get_filename_type(fw->results_logname) != LOG_FILENAME_TYPE_FILE) {
+		fprintf(stderr,
+			"Cannot specify more than one log type when "
+			"logging to stderr or stdout\n");
+		ret = FWTS_ERROR;
+		goto tidy_close;
+	}
+
 	/* Results log */
 	if ((fw->results = fwts_log_open("fwts",
 			fw->results_logname,	
diff --git a/src/lib/src/fwts_log.c b/src/lib/src/fwts_log.c
index fea7c41..3ab7930 100644
--- a/src/lib/src/fwts_log.c
+++ b/src/lib/src/fwts_log.c
@@ -315,48 +315,125 @@ void fwts_log_set_format(const char *str)
 }
 
 /*
- *  fwts_log_vprintf()
- *	printf to a log
+ *  fwts_log_type_filename_suffix()
+ *	return a filename suffix on a given log type
  */
-int fwts_log_printf(fwts_log *log,
-	const fwts_log_field field,
-	const fwts_log_level level,
-	const char *status,
-	const char *label,
-	const char *prefix,
-	const char *fmt, ...)
+static char *fwts_log_type_filename_suffix(fwts_log_type type)
 {
-	va_list	args;
-	int ret;
+	switch (type) {
+	case LOG_TYPE_JSON:
+		return ".json";
+	case LOG_TYPE_XML:
+		return ".xml";
+	case LOG_TYPE_HTML:
+		return ".html";
+	case LOG_TYPE_NONE:
+	case LOG_TYPE_PLAINTEXT:
+	default:
+		return ".log";
+	}
+}
+
+/*
+ *  fwts_log_filename_new_suffix()
+ *	return the log name with suffix based on log type
+ */
+static char *fwts_log_filename(const char *filename, fwts_log_type type)
+{
+	char *ptr;
+	char *new_name;
+	char *suffix;
+	size_t suffix_len;
+	size_t trunc_len;
+	size_t filename_len;
+
+	suffix = fwts_log_type_filename_suffix(type);
+	suffix_len = strlen(suffix);
+
+	/*
+	 * Locate an existing suffix, if it is one we recognise
+	 * then remove it and append the appropriate one
+	 */
+	ptr = rindex(filename, '.');
+	if (ptr &&
+		(!strcmp(ptr, ".log") ||
+		 !strcmp(ptr, ".json") ||
+		 !strcmp(ptr, ".xml") ||
+		 !strcmp(ptr, ".html"))) {
+
+		trunc_len = ptr - filename;
+		if ((new_name = calloc(trunc_len + suffix_len + 1, 1)) == NULL) {
+			fprintf(stderr, "Cannot allocate log name.\n");
+			return NULL;
+		}
+		strncpy(new_name, filename, trunc_len);
+		strcat(new_name, suffix); /* strcat OK because calloc zero'd all of new_name */
+		return new_name;
+	}
 
-	va_start(args, fmt);
-	ret = fwts_log_vprintf(log, field, level, status, label, prefix, fmt, args);
-	va_end(args);
+	/*
+	 * We didn't find a suffix or a known suffix, so append
+	 * the appropriate one to the given log filename
+	 */
+	filename_len = strlen(filename);
+	if ((new_name = calloc(filename_len + suffix_len + 1, 1)) == NULL) {
+		fprintf(stderr, "Cannot allocate log name.\n");
+		return NULL;
+	}
 
-	return ret;
+	strcpy(new_name, filename);
+	strcat(new_name, suffix);
+
+	return new_name;
 }
 
 /*
  *  fwts_log_vprintf()
- *	vprintf to a log
+ *	printf to a log
  */
-int fwts_log_vprintf(fwts_log *log,
+int fwts_log_printf(fwts_log *log,
 	const fwts_log_field field,
 	const fwts_log_level level,
 	const char *status,
 	const char *label,
 	const char *prefix,
-	const char *fmt,
-	va_list args)
+	const char *fmt, ...)
 {
+	va_list	args;
+	int ret = 0;
+
+	char buffer[LOG_MAX_BUF_SIZE];
+
 	if (!((field & LOG_FIELD_MASK) & fwts_log_filter))
-		return 0;
+		return ret;
+
+	if (log && log->magic == LOG_MAGIC) {
+		fwts_list_link *item;
+
+		/*
+		 * With the possibility of having multiple logs being written
+		 * to per call of fwts_log_printf() it is more efficient to
+		 * vsnprintf() here and then pass the formatted output down to
+		 * each log handler rather than re-formatting each time in each
+		 * handler
+		 */
+		va_start(args, fmt);
+		ret = vsnprintf(buffer, sizeof(buffer), fmt, args);
+		if (ret < 0)
+			return ret;
+
+		fwts_list_foreach(item, &log->log_files) {
+			fwts_log_file *log_file = fwts_list_data(fwts_log_file *, item);
+
+			if (log_file->ops && log_file->ops->print)
+				log_file->ops->print(log_file, field, level,
+					status, label, prefix, buffer);
+		}
+		log->line_number++;
 
-	if (log && log->magic == LOG_MAGIC &&
-	    log->ops && log->ops->underline)
-		return log->ops->vprintf(log, field, level, status, label, prefix, fmt, args);
-	else
-		return 0;
+		va_end(args);
+	}
+	return ret;
 }
 
 /*
@@ -365,9 +442,16 @@ int fwts_log_vprintf(fwts_log *log,
  */
 void fwts_log_underline(fwts_log *log, const int ch)
 {
-	if (log && log->magic == LOG_MAGIC &&
-	    log->ops && log->ops->underline)
-		log->ops->underline(log, ch);
+	if (log && log->magic == LOG_MAGIC) {
+		fwts_list_link *item;
+
+		fwts_list_foreach(item, &log->log_files) {
+			fwts_log_file *log_file = fwts_list_data(fwts_log_file *, item);
+
+			if (log_file->ops && log_file->ops->underline)
+				log_file->ops->underline(log_file, ch);
+		}
+	}
 }
 
 /*
@@ -376,9 +460,17 @@ void fwts_log_underline(fwts_log *log, const int ch)
  */
 void fwts_log_newline(fwts_log *log)
 {
-	if (log && log->magic == LOG_MAGIC &&
-	    log->ops && log->ops->underline)
-		log->ops->newline(log);
+	if (log && log->magic == LOG_MAGIC) {
+		fwts_list_link *item;
+
+		fwts_list_foreach(item, &log->log_files) {
+			fwts_log_file *log_file = fwts_list_data(fwts_log_file *, item);
+
+			if (log_file->ops && log_file->ops->newline)
+				log_file->ops->newline(log_file);
+		}
+		log->line_number++;
+	}
 }
 
 int fwts_log_set_owner(fwts_log *log, const char *owner)
@@ -395,96 +487,199 @@ int fwts_log_set_owner(fwts_log *log, const char *owner)
 	return FWTS_ERROR;
 }
 
+
+/*
+ *  fwts_log_section_begin()
+ *	mark a start of a named section.  For structured logging
+ *	such as XML and JSON this pushes a new named tagged section
+ */
 void fwts_log_section_begin(fwts_log *log, const char *name)
 {
-	if (log && log->magic == LOG_MAGIC &&
-	    log->ops && log->ops->section_begin)
-		log->ops->section_begin(log, name);
+	if (log && log->magic == LOG_MAGIC) {
+		fwts_list_link *item;
+
+		fwts_list_foreach(item, &log->log_files) {
+			fwts_log_file *log_file = fwts_list_data(fwts_log_file *, item);
+
+			if (log_file->ops && log_file->ops->section_begin)
+				log_file->ops->section_begin(log_file, name);
+		}
+	}
 }
 
+/*
+ *  fwts_log_section_end()
+ *	mark end of a named section.  For structured logging
+ *	such as XML and JSON this pops the end of a tagged section
+ */
 void fwts_log_section_end(fwts_log *log)
 {
-	if (log && log->magic == LOG_MAGIC &&
-	    log->ops && log->ops->section_end)
-		log->ops->section_end(log);
+	if (log && log->magic == LOG_MAGIC) {
+		fwts_list_link *item;
+
+		fwts_list_foreach(item, &log->log_files) {
+			fwts_log_file *log_file = fwts_list_data(fwts_log_file *, item);
+
+			if (log_file->ops && log_file->ops->section_end)
+				log_file->ops->section_end(log_file);
+		}
+	}
 }
 
 /*
- *  fwts_log_open()
- *	open a log file. if name is stderr or stdout, then attach log to these
- *	streams.
+ *  fwts_log_get_ops()
+ *	return log ops basedon log type
  */
-fwts_log *fwts_log_open(const char *owner, const char *name, const char *mode, fwts_log_type type)
+static fwts_log_ops *fwts_log_get_ops(fwts_log_type type)
 {
-	fwts_log *newlog;
-
-	if ((newlog = calloc(1, sizeof(fwts_log))) == NULL)
-		return NULL;
-
-	newlog->magic = LOG_MAGIC;
 	switch (type) {
 	case LOG_TYPE_JSON:
-		newlog->ops = &fwts_log_json_ops;
-		break;
+		return &fwts_log_json_ops;
 	case LOG_TYPE_PLAINTEXT:
-		newlog->ops = &fwts_log_plaintext_ops;
-		break;
+		return &fwts_log_plaintext_ops;
 	case LOG_TYPE_XML:
-		newlog->ops = &fwts_log_xml_ops;
-		break;
+		return &fwts_log_xml_ops;
 	case LOG_TYPE_HTML:
-		newlog->ops = &fwts_log_html_ops;
-		break;
+		return &fwts_log_html_ops;
 	case LOG_TYPE_NONE:
 	default:
-		newlog->ops = &fwts_log_plaintext_ops;
-		break;
+		return &fwts_log_plaintext_ops;
 	}
+}
 
-	if (owner) {
-		if ((newlog->owner = calloc(1, strlen(owner)+1)) == NULL) {
-			free(newlog);
-			return NULL;
-		}
-		strcpy(newlog->owner, owner);
-	}
+/*
+ *  fwts_log_get_filename_type()
+ *	determine the filename type
+ */
+fwts_log_filename_type fwts_log_get_filename_type(const char *filename)
+{
+	if (!strcmp(filename, "stderr"))
+		return LOG_FILENAME_TYPE_STDERR;
+	else if (!strcmp(filename, "stdout"))
+		return LOG_FILENAME_TYPE_STDOUT;
+	else
+		return LOG_FILENAME_TYPE_FILE;
+}
+
+/*
+ *  fwts_log_open()
+ *	open a log file. if name is stderr or stdout, then attach log to these
+ *	streams.
+ */
+fwts_log *fwts_log_open(
+	const char *owner,	/* Creator of the log */
+	const char *filename,	/* Log file name */
+	const char *mode,	/* open mode, see fopen() modes */
+	fwts_log_type type)	/* Log type */
+{
+	fwts_log *newlog;
+	unsigned int i;
+	char *newname;
 
-	if (strcmp("stderr", name) == 0)
-		newlog->fp = stderr;
-	else if (strcmp("stdout", name) == 0)
-		newlog->fp = stdout;
-	else if ((newlog->fp = fopen(name, mode)) == NULL) {
-		free(newlog);
+	if ((newlog = calloc(1, sizeof(fwts_log))) == NULL)
 		return NULL;
-	}
 
-	if (log_line_width) {
-		/* User has specified width, so use it */
-		newlog->line_width = log_line_width;
-	} else {
-		newlog->line_width = fwts_tty_width(fileno(newlog->fp), LOG_LINE_WIDTH);
-	}
+	newlog->magic = LOG_MAGIC;
 
-	if (newlog->ops && newlog->ops->open)
-		newlog->ops->open(newlog);
+	fwts_log_set_owner(newlog, owner);
+	fwts_list_init(&newlog->log_files);
+
+	/*
+	 *  Scan through and see which log types have been specified
+	 *  and open the log file with the appropriate ops to perform
+	 *  the logging
+	 */
+	for (i=0; i<32; i++) {
+		fwts_log_type mask = 1 << i;	/* The log type for this iteration */
+
+		/* If set then go and open up a log for this log type */
+		if (type & mask) {
+			fwts_log_file *log_file;
+
+			if ((log_file = calloc(1, sizeof(fwts_log_file))) == NULL) {
+				fwts_log_close(newlog);
+				return NULL;
+			}
+
+			log_file->type = mask;
+			log_file->ops  = fwts_log_get_ops(mask);
+			log_file->log  = newlog;
+			log_file->filename_type = fwts_log_get_filename_type(filename);
+
+			/*
+			 *  To complicate matters we can have logs being
+			 *  written to stderr, stdout or two a named file
+			 */
+			switch(log_file->filename_type) {
+			case LOG_FILENAME_TYPE_STDERR:
+				log_file->fp = stderr;
+				break;
+			case LOG_FILENAME_TYPE_STDOUT:
+				log_file->fp = stdout;
+				break;
+			case LOG_FILENAME_TYPE_FILE:
+				if ((newname = fwts_log_filename(filename, mask)) == NULL) {
+					fwts_log_close(newlog);
+					return NULL;
+				}
+				log_file->fp = fopen(newname, mode);
+				free(newname);
+
+				if (log_file->fp == NULL) {
+					fwts_log_close(newlog);
+					return NULL;
+				}
+			}
+
+			/* Fix up the log specific line width */
+			if (log_line_width) {
+				/* User has specified width, so use it */
+				log_file->line_width = log_line_width;
+			} else {
+				log_file->line_width =
+					fwts_tty_width(fileno(log_file->fp), LOG_LINE_WIDTH);
+			}
+
+			/* ..and add the log file to the list of logs */
+			fwts_list_append(&newlog->log_files, log_file);
+
+			/* ..and do the log specific opening set up */
+			if (log_file->ops && log_file->ops->open)
+				log_file->ops->open(log_file);
+		}
+	}
 
 	return newlog;
 }
 
 /*
  *  fwts_log_close()
- *	close a log file
+ *	close any opened log files, free up memory
  */
 int fwts_log_close(fwts_log *log)
 {
 	if (log && (log->magic == LOG_MAGIC)) {
-		if (log->ops && log->ops->close)
-			log->ops->close(log);
+		fwts_list_link *item;
+
+		fwts_list_foreach(item, &log->log_files) {
+			fwts_log_file *log_file = fwts_list_data(fwts_log_file *, item);
+
+			/* Do the log type specific close */
+			if (log_file->ops && log_file->ops->close)
+				log_file->ops->close(log_file);
+
+			/* Close opened log file */
+			if (log_file->fp &&
+			    log_file->filename_type == LOG_FILENAME_TYPE_FILE)
+				fclose(log_file->fp);
+		}
+
+		/* ..and free log files */
+		fwts_list_free_items(&log->log_files, free);
 
-		if (log->fp && (log->fp != stdout && log->fp != stderr))
-			fclose(log->fp);
 		if (log->owner)
 			free(log->owner);
+
 		free(log);
 	}
 	return FWTS_OK;
diff --git a/src/lib/src/fwts_log_html.c b/src/lib/src/fwts_log_html.c
index a70ac21..1ca79b8 100644
--- a/src/lib/src/fwts_log_html.c
+++ b/src/lib/src/fwts_log_html.c
@@ -37,31 +37,31 @@ typedef struct {
 static fwts_log_html_stack_t html_stack[MAX_HTML_STACK];
 static int html_stack_index = 0;
 
-static void fwts_log_html(fwts_log *log, const char *fmt, ...)
+static void fwts_log_html(fwts_log_file *log_file, const char *fmt, ...)
 {
 	va_list args;
 
 	va_start(args, fmt);
 
-	fprintf(log->fp, "%*s", html_stack_index * HTML_INDENT, "");
-	vfprintf(log->fp, fmt, args);
+	fprintf(log_file->fp, "%*s", html_stack_index * HTML_INDENT, "");
+	vfprintf(log_file->fp, fmt, args);
 
 	va_end(args);
 }
 
 
 /*
- *  fwts_log_vprintf_html()
- *	vprintf to a log
+ *  fwts_log_print_html()
+ *	print to a log
  */
-static int fwts_log_vprintf_html(fwts_log *log,
+static int fwts_log_print_html(
+	fwts_log_file *log_file,
 	const fwts_log_field field,
 	const fwts_log_level level,
 	const char *status,
 	const char *label,
 	const char *prefix,
-	const char *fmt,
-	va_list args)
+	const char *buffer)
 {
 	char *str;
 	char *style;
@@ -74,7 +74,7 @@ static int fwts_log_vprintf_html(fwts_log *log,
 	if (field & (LOG_NEWLINE | LOG_SEPARATOR | LOG_DEBUG))
 		return 0;
 
-	fwts_log_html(log, "<TR>\n");
+	fwts_log_html(log_file, "<TR>\n");
 
 	if (field & LOG_VERBATUM) {
 		code_start = "<PRE class=style_code>";
@@ -86,29 +86,24 @@ static int fwts_log_vprintf_html(fwts_log *log,
 
 	switch (field & LOG_FIELD_MASK) {
 	case LOG_ERROR:
-		fwts_log_html(log, "  <TD class=style_error>Error</TD><TD COLSPAN=2>");
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "</TD>\n");
+		fwts_log_html(log_file, "  <TD class=style_error>Error</TD>"
+			"<TD COLSPAN=2>%s</TD>\n", buffer);
 		break;
 	case LOG_WARNING:
-		fwts_log_html(log, "  <TD class=style_error>Warning</TD><TD COLSPAN=2 class=style_advice_info>%s", code_start);
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "%s</TD>\n", code_end);
+		fwts_log_html(log_file, "  <TD class=style_error>Warning</TD>"
+			"<TD COLSPAN=2 class=style_advice_info>%s%s%s</TD>\n",
+			code_start, buffer, code_end);
 		break;
 	case LOG_HEADING:
-		fwts_log_html(log, "<TD COLSPAN=2 class=style_heading>%s", code_start);
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "%s</TD>\n", code_end);
+		fwts_log_html(log_file, "<TD COLSPAN=2 class=style_heading>%s%s%s</TD>\n",
+			code_start, buffer, code_end);
 		break;
 	case LOG_INFO:
-		fwts_log_html(log, "  <TD></TD><TD COLSPAN=2 class=style_infos>%s", code_start);
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "%s</TD>\n", code_end);
+		fwts_log_html(log_file, "  <TD></TD><TD COLSPAN=2 class=style_infos>%s%s%s</TD>\n",
+			code_start, buffer, code_end);
 		break;
 	case LOG_PASSED:
-		fwts_log_html(log, "<TD class=style_passed>PASSED</TD><TD>");
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "</TD>\n");
+		fwts_log_html(log_file, "<TD class=style_passed>PASSED</TD><TD>%s</TD>\n", buffer);
 		break;
 	case LOG_FAILED:
 		switch (level) {
@@ -132,39 +127,33 @@ static int fwts_log_vprintf_html(fwts_log *log,
 		}
 		str = fwts_log_level_to_str(level);
 
-		fwts_log_html(log, "  <TD%s>%s [%s]</TD>\n", style, *status ? status : "", str);
-
-		fwts_log_html(log, "  <TD>");
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "</TD>\n");
+		fwts_log_html(log_file, "  <TD%s>%s [%s]</TD>\n", style, *status ? status : "", str);
+		fwts_log_html(log_file, "  <TD>%s</TD>\n", buffer);
 		break;
 
 	case LOG_SKIPPED:
-		fwts_log_html(log, "<TD class=style_skipped>Skipped</TD><TD>%s", code_start);
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "%s</TD>\n", code_end);
+		fwts_log_html(log_file, "<TD class=style_skipped>Skipped</TD>"
+			"<TD>%s%s%s</TD>\n", code_start, buffer, code_end);
 		break;
 
 	case LOG_SUMMARY:
-		fwts_log_html(log, "  <TD></TD><TD COLSPAN=2 class=style_summary>%s", code_start);
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "%s</TD>\n", code_end);
+		fwts_log_html(log_file, "  <TD></TD>"
+			"<TD COLSPAN=2 class=style_summary>%s%s%s</TD>\n",
+			code_start, buffer, code_end);
 		break;
 
 	case LOG_ADVICE:
-		fwts_log_html(log, "  <TD class=style_advice>Advice</TD><TD COLSPAN=2 class=style_advice_info>%s", code_start);
-		vfprintf(log->fp, fmt, args);
-		fprintf(log->fp, "%s</TD>\n", code_end);
+		fwts_log_html(log_file, "  <TD class=style_advice>Advice</TD>"
+			"<TD COLSPAN=2 class=style_advice_info>%s%s%s</TD>\n",
+			code_start, buffer, code_end);
 		break;
 
 	default:
 		break;
 	}
 
-	fwts_log_html(log, "</TR>\n");
-	fflush(log->fp);
-
-	log->line_number++;
+	fwts_log_html(log_file, "</TR>\n");
+	fflush(log_file->fp);
 
 	return 0;
 }
@@ -173,7 +162,7 @@ static int fwts_log_vprintf_html(fwts_log *log,
  *  fwts_log_underline_html()
  *	write an underline across log, using character ch as the underline
  */
-static void fwts_log_underline_html(fwts_log *log, const int ch)
+static void fwts_log_underline_html(fwts_log_file *log_file, const int ch)
 {
 	/* No-op for html */
 }
@@ -182,26 +171,26 @@ static void fwts_log_underline_html(fwts_log *log, const int ch)
  *  fwts_log_newline()
  *	write newline to log
  */
-static void fwts_log_newline_html(fwts_log *log)
+static void fwts_log_newline_html(fwts_log_file *log_file)
 {
 	/* No-op for html */
 }
 
-static void fwts_log_section_begin_html(fwts_log *log, const char *name)
+static void fwts_log_section_begin_html(fwts_log_file *log_file, const char *name)
 {
 	html_stack[html_stack_index].name = name;
 
 	if (!strcmp(name, "summary")) {
-		fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=2>Summary</TD></TR>\n");
+		fwts_log_html(log_file, "<TR><TD class=style_heading COLSPAN=2>Summary</TD></TR>\n");
 	} else if (!strcmp(name, "heading")) {
-		fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=2>Firmware Test Suite</TD></TR>\n");
+		fwts_log_html(log_file, "<TR><TD class=style_heading COLSPAN=2>Firmware Test Suite</TD></TR>\n");
 	} else if (!strcmp(name, "subtest_info")) {
-		fwts_log_html(log, "<TR><TD class=style_subtest COLSPAN=2></TD></TR>\n");
+		fwts_log_html(log_file, "<TR><TD class=style_subtest COLSPAN=2></TD></TR>\n");
 	} else if (!strcmp(name, "failure")) {
-		fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=2></TD></TR>\n");
+		fwts_log_html(log_file, "<TR><TD class=style_heading COLSPAN=2></TD></TR>\n");
 	}
 
-	fflush(log->fp);
+	fflush(log_file->fp);
 
 	if (html_stack_index < MAX_HTML_STACK)
 		html_stack_index++;
@@ -211,11 +200,11 @@ static void fwts_log_section_begin_html(fwts_log *log, const char *name)
 	}
 }
 
-static void fwts_log_section_end_html(fwts_log *log)
+static void fwts_log_section_end_html(fwts_log_file *log_file)
 {
 	if (html_stack_index > 0) {
 		html_stack_index--;
-		fflush(log->fp);
+		fflush(log_file->fp);
 	} else {
 		fprintf(stderr, "html log stack underflow.\n");
 		exit(EXIT_FAILURE);
@@ -223,15 +212,15 @@ static void fwts_log_section_end_html(fwts_log *log)
 
 }
 
-static void fwts_log_open_html(fwts_log *log)
+static void fwts_log_open_html(fwts_log_file *log_file)
 {
-	fwts_log_html(log, "<HTML>\n");
-	fwts_log_html(log, "<HEAD>\n");
-	fwts_log_html(log, "  <TITLE>fwts log</TITLE>\n");
-	fwts_log_html(log, "</HEAD>\n");
-	fwts_log_html(log, "<BODY>\n");
-	fwts_log_html(log, "<STYLE>\n");
-	fwts_log_html(log,
+	fwts_log_html(log_file, "<HTML>\n");
+	fwts_log_html(log_file, "<HEAD>\n");
+	fwts_log_html(log_file, "  <TITLE>fwts log</TITLE>\n");
+	fwts_log_html(log_file, "</HEAD>\n");
+	fwts_log_html(log_file, "<BODY>\n");
+	fwts_log_html(log_file, "<STYLE>\n");
+	fwts_log_html(log_file,
 		".style_critical { background-color: red; font-weight: bold; "
 		"text-align: center; vertical-align: center  }\n"
 		".style_high { background-color: orange; font-weight: bold; "
@@ -256,27 +245,27 @@ static void fwts_log_open_html(fwts_log *log)
 		".style_info { }\n"
 		".style_code { font-family: \"courier\",\"mono\"; font-size:0.75em; overflow:auto; "
 		"width:90%; line-height:0.82em; font-stretch:extra-condensed; word-wrap:normal }\n");
-	fwts_log_html(log, "</STYLE>\n");
-	fflush(log->fp);
+	fwts_log_html(log_file, "</STYLE>\n");
+	fflush(log_file->fp);
 
-	fwts_log_html(log, "<TABLE WIDTH=1024>\n");
-	fwts_log_html(log, "</TR>\n");
+	fwts_log_html(log_file, "<TABLE WIDTH=1024>\n");
+	fwts_log_html(log_file, "</TR>\n");
 
-	fwts_log_section_begin_html(log, "fwts");
+	fwts_log_section_begin_html(log_file, "fwts");
 }
 
-static void fwts_log_close_html(fwts_log *log)
+static void fwts_log_close_html(fwts_log_file *log_file)
 {
-	fwts_log_section_end_html(log);
+	fwts_log_section_end_html(log_file);
 
-	fwts_log_html(log, "</TABLE>\n");
-	fwts_log_html(log, "</BODY>\n");
-	fwts_log_html(log, "</HTML>\n");
-	fflush(log->fp);
+	fwts_log_html(log_file, "</TABLE>\n");
+	fwts_log_html(log_file, "</BODY>\n");
+	fwts_log_html(log_file, "</HTML>\n");
+	fflush(log_file->fp);
 }
 
 fwts_log_ops fwts_log_html_ops = {
-	.vprintf = 	 fwts_log_vprintf_html,
+	.print = 	 fwts_log_print_html,
 	.underline =	 fwts_log_underline_html,
 	.newline =	 fwts_log_newline_html,
 	.section_begin = fwts_log_section_begin_html,
diff --git a/src/lib/src/fwts_log_json.c b/src/lib/src/fwts_log_json.c
index 208847c..8dd65e4 100644
--- a/src/lib/src/fwts_log_json.c
+++ b/src/lib/src/fwts_log_json.c
@@ -40,19 +40,19 @@ static fwts_log_json_stack_t json_stack[MAX_JSON_STACK];
 static int json_stack_index = 0;
 
 /*
- *  fwts_log_vprintf_json()
- *	vprintf to a log
+ *  fwts_log_printf_son()
+ *	print to a log
  */
-static int fwts_log_vprintf_json(fwts_log *log,
+static int fwts_log_print_json(
+	fwts_log_file *log_file,
 	const fwts_log_field field,
 	const fwts_log_level level,
 	const char *status,
 	const char *label,
 	const char *prefix,
-	const char *fmt,
-	va_list args)
+	const char *buffer)
 {
-	char buffer[4096];
+	char tmpbuf[4096];
 	struct tm tm;
 	time_t now;
 	json_object *header;
@@ -69,13 +69,13 @@ static int fwts_log_vprintf_json(fwts_log *log,
 	localtime_r(&now, &tm);
 
 	header = json_object_new_object();
-	json_object_object_add(header, "line_num", json_object_new_int(log->line_number));
-	snprintf(buffer, sizeof(buffer), "%2.2d/%2.2d/%-2.2d",
+	json_object_object_add(header, "line_num", json_object_new_int(log_file->log->line_number));
+	snprintf(tmpbuf, sizeof(tmpbuf), "%2.2d/%2.2d/%-2.2d",
 		tm.tm_mday, tm.tm_mon + 1, (tm.tm_year+1900) % 100);
-	json_object_object_add(header, "date", json_object_new_string(buffer));
-	snprintf(buffer, sizeof(buffer), "%2.2d:%2.2d:%2.2d",
+	json_object_object_add(header, "date", json_object_new_string(tmpbuf));
+	snprintf(tmpbuf, sizeof(tmpbuf), "%2.2d:%2.2d:%2.2d",
 		tm.tm_hour, tm.tm_min, tm.tm_sec);
-	json_object_object_add(header, "time", json_object_new_string(buffer));
+	json_object_object_add(header, "time", json_object_new_string(tmpbuf));
 	json_object_object_add(header, "field_type",
 		json_object_new_string(fwts_log_field_to_str_full(field)));
 
@@ -92,13 +92,10 @@ static int fwts_log_vprintf_json(fwts_log *log,
 	json_object_object_add(header, "owner",
 		json_object_new_string(log->owner));
 	*/
-	vsnprintf(buffer, sizeof(buffer), fmt, args);
 	json_object_object_add(header, "log_text", json_object_new_string(buffer));
 
 	json_object_array_add(json_log, header);
 
-	log->line_number++;
-
 	return 0;
 }
 
@@ -106,7 +103,7 @@ static int fwts_log_vprintf_json(fwts_log *log,
  *  fwts_log_underline_json()
  *	write an underline across log, using character ch as the underline
  */
-static void fwts_log_underline_json(fwts_log *log, const int ch)
+static void fwts_log_underline_json(fwts_log_file *log_file, const int ch)
 {
 	/* No-op for json */
 }
@@ -115,12 +112,12 @@ static void fwts_log_underline_json(fwts_log *log, const int ch)
  *  fwts_log_newline()
  *	write newline to log
  */
-static void fwts_log_newline_json(fwts_log *log)
+static void fwts_log_newline_json(fwts_log_file *log_file)
 {
 	/* No-op for json */
 }
 
-static void fwts_log_section_begin_json(fwts_log *log, const char *name)
+static void fwts_log_section_begin_json(fwts_log_file *log_file, const char *name)
 {
 	json_object *json_obj;
 	json_object *json_log;
@@ -132,7 +129,7 @@ static void fwts_log_section_begin_json(fwts_log *log, const char *name)
 	json_stack[json_stack_index].obj = json_obj;
 	json_stack[json_stack_index].log = json_log;
 
-	if (json_stack_index > 0) 
+	if (json_stack_index > 0)
 		json_object_array_add(json_stack[json_stack_index-1].log, json_obj);
 
 	if (json_stack_index < MAX_JSON_STACK)
@@ -143,7 +140,7 @@ static void fwts_log_section_begin_json(fwts_log *log, const char *name)
 	}
 }
 
-static void fwts_log_section_end_json(fwts_log *log)
+static void fwts_log_section_end_json(fwts_log_file *log_file)
 {
 	if (json_stack_index > 0)
 		json_stack_index--;
@@ -153,29 +150,30 @@ static void fwts_log_section_end_json(fwts_log *log)
 	}
 }
 
-static void fwts_log_open_json(fwts_log *log)
+static void fwts_log_open_json(fwts_log_file *log_file)
 {
-	fwts_log_section_begin_json(log, "fwts");
+	fwts_log_section_begin_json(log_file, "fwts");
 }
 
-static void fwts_log_close_json(fwts_log *log)
+static void fwts_log_close_json(fwts_log_file *log_file)
 {
 	const char *str;
 	size_t len;
 
-	fwts_log_section_end_json(log);
+	fwts_log_section_end_json(log_file);
 
 	str = json_object_to_json_string(json_stack[0].obj);
 	len = strlen(str);
 
-	fwrite(str, 1, len, log->fp);
-	fwrite("\n", 1, 1, log->fp);
-	fflush(log->fp);
+	fwrite(str, 1, len, log_file->fp);
+	fwrite("\n", 1, 1, log_file->fp);
+	fflush(log_file->fp);
+
 	json_object_put(json_stack[0].obj);
 }
 
 fwts_log_ops fwts_log_json_ops = {
-	.vprintf = 	 fwts_log_vprintf_json,
+	.print = 	 fwts_log_print_json,
 	.underline =	 fwts_log_underline_json,
 	.newline =	 fwts_log_newline_json,
 	.section_begin = fwts_log_section_begin_json,
diff --git a/src/lib/src/fwts_log_plaintext.c b/src/lib/src/fwts_log_plaintext.c
index 44c443f..7381ae3 100644
--- a/src/lib/src/fwts_log_plaintext.c
+++ b/src/lib/src/fwts_log_plaintext.c
@@ -32,7 +32,8 @@
  *  fwts_log_header_plaintext()
  *	format up a tabulated log heading
  */
-static int fwts_log_header_plaintext(fwts_log *log,
+static int fwts_log_header_plaintext(
+	fwts_log_file *log_file,
 	char *buffer,
 	const int len,
 	const fwts_log_field field,
@@ -51,7 +52,7 @@ static int fwts_log_header_plaintext(fwts_log *log,
 			ptr++;
 			if (!strncmp(ptr, "line", 4)) {
 				n += snprintf(buffer + n, len - n,
-					"%5.5d", log->line_number);
+					"%5.5d", log_file->log->line_number);
 				ptr += 4;
 			}
 			if (!strncmp(ptr, "date", 4)) {
@@ -76,8 +77,8 @@ static int fwts_log_header_plaintext(fwts_log *log,
 					fwts_log_level_to_str(level));
 				ptr += 5;
 			}
-			if (!strncmp(ptr,"owner", 5) && log->owner) {
-				n += snprintf(buffer + n, len - n, "%-15.15s", log->owner);
+			if (!strncmp(ptr,"owner", 5) && log_file->log->owner) {
+				n += snprintf(buffer + n, len - n, "%-15.15s", log_file->log->owner);
 				ptr += 5;
 			}
 		} else {
@@ -90,19 +91,19 @@ static int fwts_log_header_plaintext(fwts_log *log,
 
 
 /*
- *  fwts_log_vprintf()
- *	vprintf to a log
+ *  fwts_log_print()
+ *	print to a log
  */
-static int fwts_log_vprintf_plaintext(fwts_log *log,
+static int fwts_log_print_plaintext(
+	fwts_log_file *log_file,
 	const fwts_log_field field,
 	const fwts_log_level level,
 	const char *status,	/* Ignored */
 	const char *label,	/* Ignored */
 	const char *prefix,
-	const char *fmt,
-	va_list args)
+	const char *buffer)
 {
-	char buffer[4096];
+	char tmpbuf[8192];
 	int n = 0;
 	int header_len;
 	int len = 0;
@@ -115,15 +116,14 @@ static int fwts_log_vprintf_plaintext(fwts_log *log,
 
 	/* This is a pain, we neen to find out how big the leading log
 	   message is, so format one up. */
-	n = header_len = fwts_log_header_plaintext(log, buffer, sizeof(buffer), field, level);
-	n += snprintf(buffer + n, sizeof(buffer) - n, "%s", prefix);
-	n += vsnprintf(buffer + n, sizeof(buffer) - n, fmt, args);
+	n = header_len = fwts_log_header_plaintext(log_file, tmpbuf, sizeof(tmpbuf), field, level);
+	n += snprintf(tmpbuf + n, sizeof(tmpbuf) - n, "%s%s", prefix, buffer);
 
 	/* Break text into multi-lines if necessary */
 	if (field & LOG_VERBATUM)
-		lines = fwts_list_from_text(buffer + header_len);
+		lines = fwts_list_from_text(tmpbuf + header_len);
 	else
-		lines = fwts_format_text(buffer + header_len, log->line_width - header_len);
+		lines = fwts_format_text(tmpbuf + header_len, log_file->line_width - header_len);
 
 	len = n;
 
@@ -133,17 +133,16 @@ static int fwts_log_vprintf_plaintext(fwts_log *log,
 		if (!(field & LOG_NO_FIELDS)) {
 			/* Re-format up a log heading with current line number which
 	 		   may increment with multiple line log messages */
-			fwts_log_header_plaintext(log, buffer, sizeof(buffer), field, level);
-			fwrite(buffer, 1, header_len, log->fp);
+			fwts_log_header_plaintext(log_file, tmpbuf, sizeof(tmpbuf), field, level);
+			fwrite(tmpbuf, 1, header_len, log_file->fp);
 		}
-		fwrite(text, 1, strlen(text), log->fp);
-		fwrite("\n", 1, 1, log->fp);
-		fflush(log->fp);
-		log->line_number++;
+		fwrite(text, 1, strlen(text), log_file->fp);
+		fwrite("\n", 1, 1, log_file->fp);
+		fflush(log_file->fp);
 		len += strlen(text) + 1;
 	}
 	fwts_text_list_free(lines);
-	
+
 	return len;
 }
 
@@ -151,11 +150,11 @@ static int fwts_log_vprintf_plaintext(fwts_log *log,
  *  fwts_log_underline_plaintext()
  *	write an underline across log, using character ch as the underline
  */
-static void fwts_log_underline_plaintext(fwts_log *log, const int ch)
+static void fwts_log_underline_plaintext(fwts_log_file *log_file, const int ch)
 {
 	int n;
 	char *buffer;
-	size_t width = log->line_width + 1;
+	size_t width = log_file->line_width + 1;
 
 	if (!((LOG_SEPARATOR & LOG_FIELD_MASK) & fwts_log_filter))
 		return;
@@ -165,14 +164,13 @@ static void fwts_log_underline_plaintext(fwts_log *log, const int ch)
 		return;	/* Unlikely, and just abort */
 
 	/* Write in leading optional line prefix */
-	n = fwts_log_header_plaintext(log, buffer, width, LOG_SEPARATOR, LOG_LEVEL_NONE);
+	n = fwts_log_header_plaintext(log_file, buffer, width, LOG_SEPARATOR, LOG_LEVEL_NONE);
 
 	memset(buffer + n, ch, width  - n);
 	buffer[width - 1] = '\n';
 
-	fwrite(buffer, 1, width, log->fp);
-	fflush(log->fp);
-	log->line_number++;
+	fwrite(buffer, 1, width, log_file->fp);
+	fflush(log_file->fp);
 
 	free(buffer);
 }
@@ -181,15 +179,14 @@ static void fwts_log_underline_plaintext(fwts_log *log, const int ch)
  *  fwts_log_newline_plaintext()
  *	write newline to log
  */
-static void fwts_log_newline_plaintext(fwts_log *log)
+static void fwts_log_newline_plaintext(fwts_log_file *log_file)
 {
-	fwrite("\n", 1, 1, log->fp);
-	fflush(log->fp);
-	log->line_number++;
+	fwrite("\n", 1, 1, log_file->fp);
+	fflush(log_file->fp);
 }
 
 fwts_log_ops fwts_log_plaintext_ops = {
-	.vprintf = 	fwts_log_vprintf_plaintext,
+	.print = 	fwts_log_print_plaintext,
 	.underline =	fwts_log_underline_plaintext,
 	.newline =	fwts_log_newline_plaintext
 };
diff --git a/src/lib/src/fwts_log_xml.c b/src/lib/src/fwts_log_xml.c
index 57b530b..19e5e94 100644
--- a/src/lib/src/fwts_log_xml.c
+++ b/src/lib/src/fwts_log_xml.c
@@ -38,19 +38,18 @@ static fwts_log_xml_stack_t xml_stack[MAX_XML_STACK];
 static int xml_stack_index = 0;
 
 /*
- *  fwts_log_vprintf_xml()
- *	vprintf to a log
+ *  fwts_log_print_xml()
+ *	print to a log
  */
-static int fwts_log_vprintf_xml(fwts_log *log,
+static int fwts_log_print_xml(
+	fwts_log_file *log_file,
 	const fwts_log_field field,
 	const fwts_log_level level,
 	const char *status,
 	const char *label,
 	const char *prefix,
-	const char *fmt,
-	va_list args)
+	const char *buffer)
 {
-	char buffer[4096];
 	struct tm tm;
 	time_t now;
 	char *str;
@@ -64,21 +63,21 @@ static int fwts_log_vprintf_xml(fwts_log *log,
 	time(&now);
 	localtime_r(&now, &tm);
 
-	fprintf(log->fp, "%*s<logentry>\n", xml_stack_index * XML_INDENT, "");
+	fprintf(log_file->fp, "%*s<logentry>\n", xml_stack_index * XML_INDENT, "");
 
-	fprintf(log->fp, "%*s<line_num>%d</line_num>\n",
+	fprintf(log_file->fp, "%*s<line_num>%d</line_num>\n",
 		(xml_stack_index + 1) * XML_INDENT,
-		"", log->line_number);
+		"", log_file->log->line_number);
 
-	fprintf(log->fp, "%*s<date>%2.2d/%2.2d/%-2.2d</date>\n",
+	fprintf(log_file->fp, "%*s<date>%2.2d/%2.2d/%-2.2d</date>\n",
 		(xml_stack_index + 1) * XML_INDENT,
 		"", tm.tm_mday, tm.tm_mon + 1, (tm.tm_year+1900) % 100);
 
-	fprintf(log->fp, "%*s<time>%2.2d:%2.2d:%2.2d</time>\n",
+	fprintf(log_file->fp, "%*s<time>%2.2d:%2.2d:%2.2d</time>\n",
 		(xml_stack_index + 1) * XML_INDENT,
 		"", tm.tm_hour, tm.tm_min, tm.tm_sec);
 
-	fprintf(log->fp, "%*s<field_type>%s</field_type>\n",
+	fprintf(log_file->fp, "%*s<field_type>%s</field_type>\n",
 		(xml_stack_index + 1) * XML_INDENT,
 		"", fwts_log_field_to_str_full(field));
 
@@ -86,26 +85,23 @@ static int fwts_log_vprintf_xml(fwts_log *log,
 	if (!strcmp(str, " "))
 		str = "None";
 
-	fprintf(log->fp, "%*s<level>%s</level>\n",
+	fprintf(log_file->fp, "%*s<level>%s</level>\n",
 		(xml_stack_index + 1) * XML_INDENT, "", str);
 
-	fprintf(log->fp, "%*s<status>%s</status>\n",
+	fprintf(log_file->fp, "%*s<status>%s</status>\n",
 		(xml_stack_index + 1) * XML_INDENT,
 		"", *status ? status : "None");
 
-	fprintf(log->fp, "%*s<failure_label>%s</failure_label>\n",
+	fprintf(log_file->fp, "%*s<failure_label>%s</failure_label>\n",
 		(xml_stack_index + 1) * XML_INDENT,
 		"", label && *label ? label : "None");
 
-	vsnprintf(buffer, sizeof(buffer), fmt, args);
-	fprintf(log->fp, "%*s<log_text>%s</log_text>\n",
+	fprintf(log_file->fp, "%*s<log_text>%s</log_text>\n",
 		(xml_stack_index + 1) * XML_INDENT,
 		"", buffer);
 
-	fprintf(log->fp, "%*s</logentry>\n", xml_stack_index * XML_INDENT, "");
-	fflush(log->fp);
-
-	log->line_number++;
+	fprintf(log_file->fp, "%*s</logentry>\n", xml_stack_index * XML_INDENT, "");
+	fflush(log_file->fp);
 
 	return 0;
 }
@@ -114,7 +110,7 @@ static int fwts_log_vprintf_xml(fwts_log *log,
  *  fwts_log_underline_xml()
  *	write an underline across log, using character ch as the underline
  */
-static void fwts_log_underline_xml(fwts_log *log, const int ch)
+static void fwts_log_underline_xml(fwts_log_file *log_file, const int ch)
 {
 	/* No-op for xml */
 }
@@ -123,17 +119,17 @@ static void fwts_log_underline_xml(fwts_log *log, const int ch)
  *  fwts_log_newline()
  *	write newline to log
  */
-static void fwts_log_newline_xml(fwts_log *log)
+static void fwts_log_newline_xml(fwts_log_file *log_file)
 {
 	/* No-op for xml */
 }
 
-static void fwts_log_section_begin_xml(fwts_log *log, const char *name)
+static void fwts_log_section_begin_xml(fwts_log_file *log_file, const char *name)
 {
 	xml_stack[xml_stack_index].name = name;
 
-	fprintf(log->fp, "%*s<%s>\n", xml_stack_index * XML_INDENT, "", name);
-	fflush(log->fp);
+	fprintf(log_file->fp, "%*s<%s>\n", xml_stack_index * XML_INDENT, "", name);
+	fflush(log_file->fp);
 
 	if (xml_stack_index < MAX_XML_STACK)
 		xml_stack_index++;
@@ -143,13 +139,13 @@ static void fwts_log_section_begin_xml(fwts_log *log, const char *name)
 	}
 }
 
-static void fwts_log_section_end_xml(fwts_log *log)
+static void fwts_log_section_end_xml(fwts_log_file *log_file)
 {
 	if (xml_stack_index > 0) {
 		xml_stack_index--;
-		fprintf(log->fp, "%*s</%s>\n", xml_stack_index * XML_INDENT,
+		fprintf(log_file->fp, "%*s</%s>\n", xml_stack_index * XML_INDENT,
 			"", xml_stack[xml_stack_index].name);
-		fflush(log->fp);
+		fflush(log_file->fp);
 	} else {
 		fprintf(stderr, "xml log stack underflow.\n");
 		exit(EXIT_FAILURE);
@@ -157,26 +153,26 @@ static void fwts_log_section_end_xml(fwts_log *log)
 
 }
 
-static void fwts_log_open_xml(fwts_log *log)
+static void fwts_log_open_xml(fwts_log_file *log_file)
 {
 	char *xml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
 
-	fwrite(xml_header, 1, strlen(xml_header), log->fp);
-	fflush(log->fp);
+	fwrite(xml_header, 1, strlen(xml_header), log_file->fp);
+	fflush(log_file->fp);
 
-	fwts_log_section_begin_xml(log, "fwts");
+	fwts_log_section_begin_xml(log_file, "fwts");
 }
 
-static void fwts_log_close_xml(fwts_log *log)
+static void fwts_log_close_xml(fwts_log_file *log_file)
 {
-	fwts_log_section_end_xml(log);
+	fwts_log_section_end_xml(log_file);
 
-	fwrite("\n", 1, 1, log->fp);
-	fflush(log->fp);
+	fwrite("\n", 1, 1, log_file->fp);
+	fflush(log_file->fp);
 }
 
 fwts_log_ops fwts_log_xml_ops = {
-	.vprintf = 	 fwts_log_vprintf_xml,
+	.print = 	 fwts_log_print_xml,
 	.underline =	 fwts_log_underline_xml,
 	.newline =	 fwts_log_newline_xml,
 	.section_begin = fwts_log_section_begin_xml,
