[PATCH 1/3] lib: rework logging and framework to allow for multiple output logs
Keng-Yu Lin
kengyu at canonical.com
Wed Jun 13 09:49:07 UTC 2012
On Mon, Jun 11, 2012 at 6:00 PM, Colin King <colin.king at canonical.com> wrote:
> From: Colin Ian King <colin.king at canonical.com>
>
> Since we now can output many different log types we should also
> allow for multiple log types to be written during a run. This involves
> some considerable re-working of the logging engine.
>
> 1. The fw->log_type is now a bit map of log_types
> 2. We add a list of log types to be written to fwts_log, this is a list
> of fwts_log_file types.
> 3. We need to re-work the log name handling so that we can open multiple
> log files with different suffixes depending on the log type.
> 4. To reduce the amount of vsnprintf() of the formatted log output we
> now handle this in the log fwts_log_printf() and pass down the formatted
> output to the different logging handlers rather than keep on re-formatting
> at the lowest logging handler layer.
>
> There are a lot of changing is this patch. I tried to break it down, but
> since there are so many interdependant changes I had to resort to one big
> patch
>
> Signed-off-by: Colin Ian King <colin.king at canonical.com>
> ---
> src/lib/include/fwts_log.h | 66 +++++--
> src/lib/src/fwts_framework.c | 94 +++++-----
> src/lib/src/fwts_log.c | 363 +++++++++++++++++++++++++++++---------
> src/lib/src/fwts_log_html.c | 133 +++++++-------
> src/lib/src/fwts_log_json.c | 52 +++---
> src/lib/src/fwts_log_plaintext.c | 63 ++++---
> src/lib/src/fwts_log_xml.c | 72 ++++----
> 7 files changed, 527 insertions(+), 316 deletions(-)
>
> 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,
> --
> 1.7.10.4
>
Acked-by: Keng-Yu Lin <kengyu at canonical.com>
More information about the fwts-devel
mailing list