Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.






RTF Logging

Posted by Daishim, 11 December 2006 · 60 views

Based upon the RTF article hosted HERE on GameDev, I have created a simple log interface and RTF logging implementation. I'm experimenting with different types of logging and wanted to keep a unified interface. This interface can be expanded into HTML, XML, or other formats fairly easy.

The current incarnation supports rudimentary logging thresholds based on message types and supports macro interfaces. Any constructive criticism and suggestions is welcome.

Download zip of source, or check it out below.

app_log.h <Log_Interface>

#ifndef APP_LOG_H
#define APP_LOG_H

/*
*****************************************************************************
* LOG INTERFACE OBJECT *
* Written by: Jonathan Bender *
* Last update: December 11, 2006 *
* *
* Usage: This is the interface object for logging objects. You can *
* implement custom logging objects on top of this interface to *
* provide a common interface for you projects to plug in different *
* types of logging systems. *
* *
* Disclaimer: This code is free for use in personal projects for *
* learning purposes. This code is not intended for *
* commercial use and is not final nor free of bugs. This code *
* is provided as is and maintains no warranty. If you have any *
* questions, contact Daishim @ GameDev.net. *
*****************************************************************************
*/


#include <string> // STL strings

using std::string;

// Functionality
#define LOG_ERRORS 1
#define LOG_WARNINGS 1
#define LOG_TRACES 1
#define LOG_INFOS 1
#define LOG_DEBUGS 1
//

// Type def UInt if not already
#ifndef UINT_DEF
typedef unsigned int UInt;
#endif
//

// Log pointer alias
#define LOG_ALIAS Logger
//

// Log object
class App_Log; // Class definition is coming
extern App_Log *LOG_ALIAS; // Pointer to log is external
//

// Macro functions for quicker use
#ifdef LOG_ERRORS
#define LOG_ERROR(Message) LOG_ALIAS->Insert(GLMT_ERROR, __FUNCTION__, Message)
#else
#define LOG_ERROR(Message)
#endif

#ifdef LOG_WARNINGS
#define LOG_WARNING(Message) LOG_ALIAS->Insert(GLMT_WARNING, __FUNCTION__, Message)
#else
#define LOG_WARNING(Message)
#endif

#ifdef LOG_TRACES
#define LOG_TRACE(Message) LOG_ALIAS->Insert(GLMT_TRACE, __FUNCTION__, Message)
#else
#define LOG_TRACE(Message)
#endif

#ifdef LOG_INFOS
#define LOG_INFO(Message) LOG_ALIAS->Insert(GLMT_INFO, __FUNCTION__, Message)
#else
#define LOG_INFO(Message)
#endif

#ifdef LOG_DEBUGS
#define LOG_DEBUG(Message) LOG_ALIAS->Insert(GLMT_DEBUG, __FUNCTION__, Message)
#else
#define LOG_DEBUG(Message)
#endif

#define LOG_INIT(File) LOG_ALIAS->Initialize(File)
//

/*
#define Log(Type, Message) LOG_ALIAS->Insert(Type, __FUNCTION__, Message)
#define LogNO(Type, Message) LOG_ALIAS->Insert(Type, Message)
#define LogV(Type, Message, Value) LOG_ALIAS->InsertV(Type, __FUNCTION__, Message, Value)
#define LogVNO(Type, Message, Value) LOG_ALIAS->InsertV(Type, Message, Value)
*/

//

// Log message types
enum App_Log_Type {GLMT_REGULAR, GLMT_TRACE, GLMT_ATTEMPT, GLMT_SUCCESS, GLMT_ERROR, GLMT_WARNING, GLMT_INFO, GLMT_DEBUG};
//

// Log interface object
class App_Log
{
protected:
App_Log(void) { /* Empty */ } // Constructor
~App_Log(void) { /* Empty */ } // Destructor

public:
// External initialization/shutdown methods
virtual bool Initialize(const string &Filename) = 0; // Open the log file
virtual void Close(void) = 0; // Close the log file
//

// External insertion methods
virtual void Insert(string &Text) = 0; // Insert line of text into log
virtual void Insert(const char *Text) = 0; // Insert line of text into log

virtual void Insert(App_Log_Type Type, string &Text) = 0; // Insert line text of type with origin
virtual void Insert(App_Log_Type Type, const char *Text) = 0; // Insert line text of type with origin

virtual void Insert(App_Log_Type Type, string &Origin, string &Text) = 0; // Insert line of text into log with origin
virtual void Insert(App_Log_Type Type, const char *Origin, const char *Text) = 0; // Insert line of text into log with origin

virtual void InsertV(App_Log_Type Type, string &Text, int Value) = 0; // Insert line of text with signed integer value
virtual void InsertV(App_Log_Type Type, const char *Text, int Value) = 0; // Insert line of text with signed integer value

virtual void InsertV(App_Log_Type Type, string &Origin, string &Text, int Value) = 0; // Insert line of text with origin and signed integer value
virtual void InsertV(App_Log_Type Type, const char *Origin, const char *Text, int Value) = 0; // Insert line of text with origin and signed integer value

virtual void InsertV(App_Log_Type Type, string &Text, UInt Value) = 0; // Insert line of text with unsigned integer value
virtual void InsertV(App_Log_Type Type, const char *Text, UInt Value) = 0; // Insert line of text with unsigned integer value

virtual void InsertV(App_Log_Type Type, string &Origin, string &Text, UInt Value) = 0; // Insert line of text with origin and unsigned integer value
virtual void InsertV(App_Log_Type Type, const char *Origin, const char *Text, UInt Value) = 0; // Insert line of text with origin and unsigned integer value

virtual void InsertV(App_Log_Type Type, string &Text, string &Value) = 0; // Insert line of text with string value
virtual void InsertV(App_Log_Type Type, const char *Text, const char *Value) = 0; // Insert line of text with string value

virtual void InsertV(App_Log_Type Type, string &Origin, string &Text, string &Value) = 0; // Insert line of text with origin and string value
virtual void InsertV(App_Log_Type Type, const char *Origin, const char *Text, const char *Value) = 0; // Insert line of text with origin and string value
//
};

#endif /* APP_LOG_H */



app_log_rtf.h

#ifndef APP_LOG_RTF_H
#define APP_LOG_RTF_H

/*
*****************************************************************************
* RTF LOG OBJECT *
* Written by: Jonathan Bender *
* Last update: December 11, 2006 *
* *
* Usage: This object extends the App_Log object to provide an rich text *
* logger. Include the source and header, along with the interface *
* header, in your project. You may then use this log object with *
* the macros in the interface object header. *
* *
* Desctription: This log was designed for functionality and formatted *
* output text, not speed. For a faster logging system, use a *
* plain text logger (not included yet). *
* *
* Disclaimer: This code is free for use in personal projects for *
* learning purposes. This code is not intended for *
* commercial use and is not final nor free of bugs. This code *
* is provided as is and maintains no warranty. If you have any *
* questions, contact Daishim @ GameDev.net. *
*****************************************************************************
*/


#include <fstream> // STL file streams

#include "app_log.h" // Log interace

using std::ofstream;

class App_Log_RTF : public App_Log
{
private:
// Log data
string m_Filename; // Log filename
ofstream *m_File; // File stream of log file
//

// File output methods
void Write_To_Log(const string &Text); // Commit a string of text to the log file
void Write_Header(void); // Write the RTF file header
//

// Internal insertion methods
void Insert_Value(string &Text, int Value); // Insert signed integer value into string
void Insert_Value(string &Text, UInt Value); // Insert unsigned integer value into string
void Insert_Value(string &Text, string &Value); // Insert string value into string
//

// Formatting methods
void Swap_Tags(string &Text, const string &Clean_Tag, const string &RTF_Tag); // Swaps clean tags for RTF tags
void Format(string &Text); // Formatting instructions
//

public:
App_Log_RTF(void); // Constructor
~App_Log_RTF(void); // Destructor

// External initialization/shutdown methods
bool Initialize(const string &Filename = "log.rtf"); // Open the log file
void Close(void); // Close the log file
//

// External insertion methods
void Insert(string &Text); // Insert line of text into log
void Insert(const char *Text); // Insert line of text into log

void Insert(App_Log_Type Type, string &Text); // Insert line text of type with origin
void Insert(App_Log_Type Type, const char *Text); // Insert line text of type with origin

void Insert(App_Log_Type Type, string &Origin, string &Text); // Insert line of text into log with origin
void Insert(App_Log_Type Type, const char *Origin, const char *Text); // Insert line of text into log with origin

void InsertV(App_Log_Type Type, string &Text, int Value); // Insert line of text with signed integer value
void InsertV(App_Log_Type Type, const char *Text, int Value); // Insert line of text with signed integer value

void InsertV(App_Log_Type Type, string &Origin, string &Text, int Value); // Insert line of text with origin and signed integer value
void InsertV(App_Log_Type Type, const char *Origin, const char *Text, int Value); // Insert line of text with origin and signed integer value

void InsertV(App_Log_Type Type, string &Text, UInt Value); // Insert line of text with unsigned integer value
void InsertV(App_Log_Type Type, const char *Text, UInt Value); // Insert line of text with unsigned integer value

void InsertV(App_Log_Type Type, string &Origin, string &Text, UInt Value); // Insert line of text with origin and unsigned integer value
void InsertV(App_Log_Type Type, const char *Origin, const char *Text, UInt Value); // Insert line of text with origin and unsigned integer value

void InsertV(App_Log_Type Type, string &Text, string &Value); // Insert line of text with string value
void InsertV(App_Log_Type Type, const char *Text, const char *Value); // Insert line of text with string value

void InsertV(App_Log_Type Type, string &Origin, string &Text, string &Value); // Insert line of text with origin and string value
void InsertV(App_Log_Type Type, const char *Origin, const char *Text, const char *Value); // Insert line of text with origin and string value
//
};

#endif /* APP_LOG_RTF_H */



app_log_rtf.cpp

/*
*****************************************************************************
* RTF LOG OBJECT *
* Written by: Jonathan Bender *
* Last update: December 11, 2006 *
* *
* Usage: This object extends the App_Log object to provide an rich text *
* logger. Include the source and header, along with the interface *
* header, in your project. You may then use this log object with *
* the macros in the interface object header. *
* *
* Desctription: This log was designed for functionality and formatted *
* output text, not speed. For a faster logging system, use a *
* plain text logger (not included yet). *
* *
* Disclaimer: This code is free for use in personal projects for *
* learning purposes. This code is not intended for *
* commercial use and is not final nor free of bugs. This code *
* is provided as is and maintains no warranty. If you have any *
* questions, contact Daishim @ GameDev.net. *
*****************************************************************************
*/


#include <fstream> // STL file streams
#include <string> // STL strings
#include <sstream> // STL string streams

#include "app_log_rtf.h" // App log object

using std::string;
using std::ofstream;
using std::stringstream;

// Log object
App_Log_RTF RTF_Log;
App_Log *Logger = reinterpret_cast<App_Log *>(&RTF_Log);
//

// Constructor, set log file and
App_Log_RTF::App_Log_RTF(void)
{
// Initialize all members to NULL/0
m_File = NULL;
}

// Destructor
App_Log_RTF::~App_Log_RTF(void)
{
// If log is open
if(m_File)
Close(); // Close it
}

/////////////////////////
// File output methods //
/////////////////////////

// Commit a string of text to the log file
void App_Log_RTF::Write_To_Log(const string &Text)
{
// Write text to file
m_File->write(Text.c_str(), (std::streamsize) Text.length());
m_File->flush();
}

// Write the RTF file header
void App_Log_RTF::Write_Header(void)
{
// Write RTF header
Write_To_Log("{\\rtf1\\ansi\\deff0{\\fonttbl{\\f0 Times New Roman;}}\\fs20\n");

// Write color table
Write_To_Log("{\\colortbl;\n"); // Black
Write_To_Log("\\red255\\green255\\blue255;\n"); // White
Write_To_Log("\\red128\\green128\\blue128;\n"); // Grey
Write_To_Log("\\red255\\green0\\blue0;\n"); // Red
Write_To_Log("\\red0\\green255\\blue0;\n"); // Green
Write_To_Log("\\red0\\green0\\blue255;\n"); // Blue
Write_To_Log("\\red0\\green128\\blue0;\n"); // Dark green
Write_To_Log("\\red255\\green128\\blue0;\n"); // Orange
Write_To_Log("\\red0\\green200\\blue200;\n"); // Blue-green
Write_To_Log("}\n");

// Write logging started message
Insert("== Start Log ==\n\n");

// Blank line spacer
Insert("\n");
}

////////////////////////////////
// Internal insertion methods //
////////////////////////////////

// Insert signed integer value into string
void App_Log_RTF::Insert_Value(string &Text, int Value)
{
unsigned int Position = 0;
string Text_Value;
stringstream Stream;

Stream << Value;
Text_Value = Stream.str();

if((Position = (unsigned int) Text.find("%i", 0)) != string::npos)
Text.replace(Position, 2, Stream.str());
}

// Insert unsigned integer value into string
void App_Log_RTF::Insert_Value(string &Text, UInt Value)
{
unsigned int Position = 0;
string Text_Value;
stringstream Stream;

Stream << Value;
Text_Value = Stream.str();

if((Position = (unsigned int) Text.find("%i", 0)) != string::npos)
Text.replace(Position, 2, Stream.str());
}

// Insert string value into string
void App_Log_RTF::Insert_Value(string &Text, string &Value)
{
unsigned int Position = 0;

if((Position = (unsigned int) Text.find("%s", 0)) != string::npos)
Text.replace(Position, 2, Value.c_str());
}

////////////////////////
// Formatting methods //
////////////////////////

// Swaps clean tags for RTF tags
void App_Log_RTF::Swap_Tags(string &Text, const string &Clean_Tag, const string &RTF_Tag)
{
unsigned int Position = 0;

// Find each occurance of the clean tag
while((Position = (unsigned int) Text.find(Clean_Tag, (size_t) Position)) != string::npos)
{
Text.replace(Position, Clean_Tag.length(), RTF_Tag); // Replace clean tag with RTF tag
Position += (unsigned int) (Clean_Tag.length() > RTF_Tag.length() ? Clean_Tag.length() + 1 : RTF_Tag.length()); // Set position to after the clean tag
}
}

// Formatting instructions
void App_Log_RTF::Format(string &Text)
{
// Special formatting
Swap_Tags(Text, "\\", "\\\\"); // Convert slash to single slash
Swap_Tags(Text, "{", "\\{"); // Convert open brace to RTF open brace
Swap_Tags(Text, "}", "\\}"); // Convert close brace to RTF close brace

// Text coloring
Swap_Tags(Text, "[BLACK]", "\\cf0 "); // Black
Swap_Tags(Text, "[WHITE]", "\\cf1 "); // White
Swap_Tags(Text, "[GREY]", "\\cf2 "); // Grey
Swap_Tags(Text, "[RED]", "\\cf3 "); // Red
Swap_Tags(Text, "[GREEN]", "\\cf4 "); // Green
Swap_Tags(Text, "[BLUE]", "\\cf5 "); // Blue
Swap_Tags(Text, "[DKGREEN]", "\\cf6 "); // Dark green
Swap_Tags(Text, "[ORANGE]", "\\cf7 "); // Orange
Swap_Tags(Text, "[CYAN]", "\\cf8 "); // Blue-green

// Type formatting
Swap_Tags(Text, "[B]", "\\b "); // Bold start
Swap_Tags(Text, "[/B]", "\\b0 "); // Bold end
Swap_Tags(Text, "[I]", "\\i "); // Italicized start
Swap_Tags(Text, "[/I]", "\\i0 "); // Italicized end

// Object formatting
Swap_Tags(Text, "<", "\\b <"); // Convert object open carrot to bold object open carrot
Swap_Tags(Text, ">", ">\\b0 "); // Convert object close carrot to not bold then close carrot

// General formatting
Text.insert(0, "{\\pard "); // Prepend line starter

if(Text[Text.length() - 1] == '\n')
{
Text.replace(Text.length() - 1, 6, "\\par}\n"); // Append line ender with newline
//Text.insert(Text.length(), "\\par}\n");
}
else
{
Text.insert(Text.length(), "}\n"); // Append line ender without newline
}
}

//////////////////////////////////////////////
// External initialization/shutdown methods //
//////////////////////////////////////////////

// Open the log file
bool App_Log_RTF::Initialize(const string &Filename)
{
bool Success = true;

m_Filename = Filename; // Copy filename to local container

// Attempt to create new file stream
m_File = new ofstream(Filename.c_str());

if(!(*m_File))
{
// Failed to open file
Success = false;

// Destroy the file stream
delete m_File;
m_File = NULL;
}
else
{
// Write log file header
Write_Header();
}

return Success;
}

// Close the log file
void App_Log_RTF::Close(void)
{
// If file is open
if(m_File)
{
Insert("\n"); // Write blank line as spacer
Insert("== End Of Log ==\n"); // Write end of log file message
Write_To_Log("}"); // Write RTF footer

// Close file
m_File->close();

// Destroy file stream
delete m_File;
m_File = NULL;
}
}

////////////////////////////////
// External insertion methods //
////////////////////////////////

// Insert text into log
void App_Log_RTF::Insert(string &Text)
{
// If file is open
if(m_File)
{
Format(Text); // Format incoming text RTF style
Write_To_Log(Text); // Write text to file
}
}

// Insert text into log
void App_Log_RTF::Insert(const char *Text)
{
string SText(Text);

// If file is open
if(m_File)
{
Format(SText); // Format incoming text RTF style
Write_To_Log(SText); // Write text to file
}
}

// Insert line of text of type into log (newline after text)
void App_Log_RTF::Insert(App_Log_Type Type, string &Text)
{
// If file is open
if(m_File)
{
if(Type == GLMT_TRACE)
{
Text.insert(0, "[GREY]"); // Trace messages are grey
}
else if(Type == GLMT_ATTEMPT)
{
Text.insert(0, "[BLUE]"); // Code attempt messages are blue

if(Text[Text.length() - 1] != '\n')
Text.insert(Text.length(), ": ");
}
else if(Type == GLMT_SUCCESS)
{
Text.insert(0, "[B][BLUE]"); // Success messages are bolded blue
}
else if(Type == GLMT_ERROR)
{
Text.insert(0, "[RED]"); // Error messages are red
}
else if(Type == GLMT_WARNING)
{
Text.insert(0, "[ORANGE]"); // Warning messages are orange
}
else if(Type == GLMT_INFO)
{
Text.insert(0, "[DKGREEN]"); // Info messages are dark green
}
else if(Type == GLMT_DEBUG)
{
Text.insert(0, "[CYAN]"); // Debug messages are blue-green
}
else
{
Text.insert(0, "[BLACK]"); // Plain/no type messages are black
}

Format(Text); // Format incoming text RTF style
Write_To_Log(Text); // Write text to file
}
}

// Insert line of text of type into log (newline after text)
void App_Log_RTF::Insert(App_Log_Type Type, const char *Text)
{
string SText(Text);

// If file is open
if(m_File)
{
if(Type == GLMT_TRACE)
{
SText.insert(0, "[GREY]"); // Trace messages are grey
}
else if(Type == GLMT_ATTEMPT)
{
SText.insert(0, "[BLUE]"); // Code attempt messages are blue

// Attempt message follows with : and then the message
if(SText[SText.length() - 1] != '\n')
SText.insert(SText.length(), ": ");
}
else if(Type == GLMT_SUCCESS)
{
SText.insert(0, "[B][BLUE]"); // Success messages are bolded blue
}
else if(Type == GLMT_ERROR)
{
SText.insert(0, "[RED]"); // Error messages are red
}
else if(Type == GLMT_WARNING)
{
SText.insert(0, "[ORANGE]"); // Warning messages are orange
}
else if(Type == GLMT_INFO)
{
SText.insert(0, "[DKGREEN]"); // Info messages are dark green
}
else
{
SText.insert(0, "[BLACK]"); // Plain/no type messages are black
}

Format(SText); // Format incoming text RTF style
Write_To_Log(SText); // Write text to file
}
}

// Insert line of text into log with origin
void App_Log_RTF::Insert(App_Log_Type Type, string &Origin, string &Text)
{
Origin.insert(0, "<");
Origin.insert(Origin.length(), "> ");

Text.insert(0, Origin);

Insert(Type, Text);
}

// Insert line of text into log with origin
void App_Log_RTF::Insert(App_Log_Type Type, const char *Origin, const char *Text)
{
string SOrigin(Origin);
string SText(Text);

SOrigin.insert(0, "<");
SOrigin.insert(SOrigin.length(), "> ");

SText.insert(0, SOrigin);

Insert(Type, SText);
}

// Insert line of text with signed integer value
void App_Log_RTF::InsertV(App_Log_Type Type, string &Text, int Value)
{
Insert_Value(Text, Value);
Insert(Type, Text);
}

// Insert line of text with signed integer value
void App_Log_RTF::InsertV(App_Log_Type Type, const char *Text, int Value)
{
string SText(Text);

Insert_Value(SText, Value);
Insert(Type, SText);
}

// Insert line of text with origin and signed integer value
void App_Log_RTF::InsertV(App_Log_Type Type, string &Origin, string &Text, int Value)
{
Insert_Value(Text, Value);
Insert(Type, Origin, Text);
}

// Insert line of text with origin and signed integer value
void App_Log_RTF::InsertV(App_Log_Type Type, const char *Origin, const char *Text, int Value)
{
string SOrigin(Origin);
string SText(Text);

Insert_Value(SText, Value);
Insert(Type, SOrigin, SText);
}

// Insert line of text with unsigned integer value
void App_Log_RTF::InsertV(App_Log_Type Type, string &Text, UInt Value)
{
Insert_Value(Text, Value);
Insert(Type, Text);
}

// Insert line of text with unsigned integer value
void App_Log_RTF::InsertV(App_Log_Type Type, const char *Text, UInt Value)
{
string SText(Text);

Insert_Value(SText, Value);
Insert(Type, SText);
}

// Insert line of text with origin and unsigned integer value
void App_Log_RTF::InsertV(App_Log_Type Type, string &Origin, string &Text, UInt Value)
{
Insert_Value(Text, Value);
Insert(Type, Origin, Text);
}

// Insert line of text with origin and unsigned integer value
void App_Log_RTF::InsertV(App_Log_Type Type, const char *Origin, const char *Text, UInt Value)
{
string SOrigin(Origin);
string SText(Text);

Insert_Value(SText, Value);
Insert(Type, SOrigin, SText);
}

// Insert line of text with string value
void App_Log_RTF::InsertV(App_Log_Type Type, string &Text, string &Value)
{
Insert_Value(Text, Value);
//Format(Text);
Insert(Type, Text);
}

// Insert line of text with string value
void App_Log_RTF::InsertV(App_Log_Type Type, const char *Text, const char *Value)
{
string SText(Text);
string SValue(Value);

Insert_Value(SText, SValue);
//Format(Text);
Insert(Type, SText);
}

// Insert line of text with origin and string value
void App_Log_RTF::InsertV(App_Log_Type Type, string &Origin, string &Text, string &Value)
{
Insert_Value(Text, Value);
//Format(Text);
Insert(Type, Origin, Text);
}

// Insert line of text with origin and string value
void App_Log_RTF::InsertV(App_Log_Type Type, const char *Origin, const char *Text, const char *Value)
{
string SOrigin(Origin);
string SText(Text);
string SValue(Value);

Insert_Value(SText, SValue);
//Format(Text);
Insert(Type, SOrigin, SText);
}






November 2014 »

S M T W T F S
      1
2345678
9101112131415
16171819202122
23 242526272829
30      

Recent Entries

Recent Comments

Recent Entries

Recent Comments

PARTNERS