Creating flexible logging system which supports XML and plain

text. Work under progress.
This commit is contained in:
Markus Kauppila 2011-06-21 19:31:46 +03:00
parent f578687b3d
commit ac07ad67d9
5 changed files with 426 additions and 333 deletions

View file

@ -23,6 +23,8 @@
#include "logger.h"
#include "xml.h"
#include <SDL/SDL.h>
#include <stdio.h>
@ -30,281 +32,6 @@
#include <string.h>
#include <stdarg.h>
/* \todo
* - Make XML (and relevant comparisons) case-insensitive
*/
static int xml_enabled = 1;
static int loggingPriority = 0;
static int nestingDepth = 0;
/*! Definitions of log priorities */
typedef enum Priority {
VERBOSE,
DEFAULT,
} Priority;
/*! Function pointer definitions. \todo Move to logger.h */
typedef int (*LogOutputFp)(char *);
typedef int (*LogInitFp)(LogOutputFp, Priority);
typedef int (*LogCleanUptFp)(void);
typedef int (*StartTagFp)(Priority, const char *);
typedef int (*EndTagFp)(Priority, const char *);
typedef int (*TagFp)(Priority, const char *, const char *, ...);
/*! Function pointer to output function */
static LogOutputFp OutputFp = NULL;
/*! Definitions for tag styles used in Tagify() */
#define TAG_START 0x00000001
#define TAG_END 0x00000002
#define TAG_BOTH (TAG_START & TAG_END)
/*! Function prototypes \todo move to xml_logger.h */
int XMLStartTag(Priority priority, const char *tag);
int XMLEndTag(Priority priority, const char *tag);
int LogGenericOutput(char *message);
/*!
* Defines structure used for "counting" open XML-tags
*/
typedef struct TagList {
const char *tag;
struct TagList *next;
} TagList;
static TagList *openTags = NULL;
/*!
* Prepend the open tags list
*
* \return On error returns non-zero value, otherwise zero will returned
*/
static int
AddOpenTag(const char *tag)
{
TagList *openTag = SDL_malloc(sizeof(TagList));
if(openTag == NULL) {
return 1;
}
memset(openTag, 0, sizeof(TagList));
openTag->tag = tag; // Should be fine without malloc?
openTag->next = openTags;
openTags = openTag;
return 0;
}
/*!
* Removes the first tag from the open tag list
*
* \return On error returns non-zero value, otherwise zero will returned
*/
static int
RemoveOpenTag(const char *tag)
{
if(openTags == NULL) {
return 1;
}
int retVal = 0;
// Tag should always be the same as previously opened tag
// It prevents opening and ending tag mismatch
if(SDL_strcmp(openTags->tag, tag) == 0) {
TagList *openTag = openTags;
openTags = openTags->next;
free(openTag);
} else {
printf("Debug | RemoveOpenTag(): open/end tag mismatch");
retVal = 1;
}
return retVal;
}
/*!
* Debug function. Prints the contents of the open tags list.
*/
static void
PrintOpenTags()
{
printf("\nOpen tags:\n");
TagList *openTag = NULL;
for(openTag = openTags; openTag; openTag = openTag->next) {
printf("\ttag: %s\n", openTag->tag);
}
}
/*!
* Initializes the XML-logger for creating test reports in XML.
*
* \return Error code. \todo
*/
int
XMLInit(LogOutputFp logOutputFp, Priority priority)
{
OutputFp = logOutputFp;
loggingPriority = priority;
//! make "doctype" work with priority level?
OutputFp("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
XMLStartTag(DEFAULT, "testlog");
}
/*!
* Cleans up the logger and closes all open XML-tags
*
* \return Error code. \todo
*/
int
XMLCleanUp()
{
// Close the open tags
TagList *openTag = openTags;
while(openTag) {
TagList *temp = openTag->next;
XMLEndTag(DEFAULT, openTag->tag);
openTag = temp;
}
}
/*!
* Forms a valid XML-tag based on the given parameters
*
* \param tag XML-tag to create
* \param tagStyle Do start or end tag, or both.
* \param message text content of the tags
*
* \return Well-formed XML tag
*/
static char *
Tagify(const char *tag, const int tagStyle, const char *message)
{
// buffer simplifies the creation of the string
const int bufferSize = 1024;
char buffer[bufferSize];
memset(buffer, 0, bufferSize);
if(tagStyle & TAG_START) {
strcat(buffer, "<");
strcat(buffer, tag);
strcat(buffer, ">");
}
if(message) {
strcat(buffer, message);
}
if(tagStyle & TAG_END) {
strcat(buffer, "</");
strcat(buffer, tag);
strcat(buffer, ">");
}
const int size = SDL_strlen(buffer) + 1;
char *newTag = SDL_malloc(size * sizeof(char));
memset(newTag, 0, size * sizeof(char));
memcpy(newTag, buffer, size);
return newTag;
}
/*!
* Creates and outputs an start tag
*
* \param priority Priority of the tag
* \param tag Tag for outputting
*
* \return Error code. Non-zero on failure. Zero on success
*/
int
XMLStartTag(Priority priority, const char *tag)
{
if(priority < loggingPriority) {
return 1;
}
AddOpenTag(tag);
char *newTag = Tagify(tag, TAG_START, NULL);
OutputFp(newTag);
SDL_free(newTag);
nestingDepth++;
}
/*!
* Creates and outputs an end tag
*
* \param priority Priority of the tag
* \param tag Tag for outputting
*
* \return Error code. Non-zero on failure. Zero on success
*/
int
XMLEndTag(Priority priority, const char *tag)
{
/*
Do it before priority check, so incorrect usage of
priorities won't mess it up (?)
*/
nestingDepth--;
if(priority < loggingPriority) {
return 1;
}
RemoveOpenTag(tag);
char *newTag = Tagify(tag, TAG_END, NULL);
OutputFp(newTag);
SDL_free(newTag);
}
/*!
* Creates an XML-tag including start and end tags and text content
* between them.
*
* \param priority Priority of the tag
* \param tag Tag for outputting
* \param fmt Text content of tag as variadic parameter list
*
* \return Error code. Non-zero on failure. Zero on success
*/
int
XMLTag(Priority priority, const char *tag, const char *fmt, ...)
{
if(priority < loggingPriority) {
return 1;
}
const int bufferSize = 1024;
char buffer[bufferSize];
memset(buffer, 0, bufferSize);
va_list list;
va_start(list, fmt);
vsnprintf(buffer, bufferSize, fmt, list);
va_end(list);
char *newTag = Tagify(tag, TAG_BOTH, buffer);
//LogGenericOutput(newTag);
OutputFp(newTag);
SDL_free(newTag);
}
/*!
* Prints the given message to stderr. Function adds nesting
* to the output.
@ -312,33 +39,76 @@ XMLTag(Priority priority, const char *tag, const char *fmt, ...)
* \return Possible error value (\todo)
*/
int
LogGenericOutput(char *message)
LogGenericOutput(const char *message)
{
int depth = nestingDepth;
/*
int depth = indentDepth;
while(depth--) {
fprintf(stderr, " ");
}
*/
fprintf(stderr, "%s\n", message);
fflush(stderr);
}
void
RunStarted(LogOutputFp outputFn, const char *runnerParameters, time_t eventTime)
{
XMLOpenDocument("testlog", outputFn);
XMLOpenElement("parameters");
XMLAddContent(runnerParameters);
XMLCloseElement("parameters");
}
/*! Quick Dummy functions for testing non-xml output. \todo put to proper place*/
int DummyInit(LogOutputFp output, Priority priority) {
return 0;
void
RunEnded(time_t endTime, time_t totalRuntime)
{
XMLCloseDocument();
}
int DummyCleanUp() {
return 0;
void
SuiteStarted(const char *suiteName, time_t eventTime)
{
XMLOpenElement("suite");
XMLOpenElement("eventTime");
//XMLAddContent(evenTime);
XMLCloseElement("eventTime");
}
int DummyStartTag(Priority priority, const char *tag) {
return 0;
void
SuiteEnded(int testsPassed, int testsFailed, int testsSkipped,
double endTime, time_t totalRuntime)
{
XMLCloseElement("suite");
}
int DummyEndTag(Priority priority, const char *tag) {
return 0;
void
TestStarted(const char *testName, const char *testDescription, time_t startTime)
{
}
int DummyTag(Priority priority, const char *tag, const char *fmt, ...) {
return 0;
void
TestEnded(const char *testName, const char *testDescription, int testResult,
int numAsserts, time_t endTime, time_t totalRuntime)
{
}
void
Assert(const char *assertName, int assertResult, const char *assertMessage,
time_t eventTime)
{
}
void
Log(const char *logMessage, time_t eventTime)
{
}
@ -348,50 +118,10 @@ int DummyTag(Priority priority, const char *tag, const char *fmt, ...) {
int
main(int argc, char *argv[])
{
LogInitFp LogInit = NULL;
LogCleanUptFp LogCleanUp = NULL;
StartTagFp StartTag = NULL;
EndTagFp EndTag = NULL;
TagFp Tag = NULL;
if(xml_enabled) {
// set logger functions to XML
LogInit = XMLInit;
LogCleanUp = XMLCleanUp;
StartTag = XMLStartTag;
EndTag = XMLEndTag;
Tag = XMLTag;
} else {
// When no XML-output is desired, dummy functions are used
LogInit = DummyInit;
LogCleanUp = DummyCleanUp;
StartTag = DummyStartTag;
EndTag = DummyEndTag;
Tag = DummyTag;
}
LogInit(LogGenericOutput, VERBOSE);
StartTag(DEFAULT, "hello");
StartTag(DEFAULT, "world");
EndTag(DEFAULT, "world");
//EndTag(DEFAULT, "hello");
LogCleanUp();
#if 0
XMLStartTag("log");
XMLStartTag("suite");
XMLStartTag("test");
XMLEndTag("test");
XMLEndTag("suite");
PrintOpenTags();
#endif
RunStarted(LogGenericOutput, "All the data from harness", 0);
SuiteStarted("Suite data here", 0);
SuiteEnded(0, 0, 0, 0.0f, 0);
RunEnded(0, 0);
return 0;
}