Logging

[ LiB ]

As a MUD programmer, logging errors and other types of events is somewhat important. Because of this, I've created a simple log class, which is small and elegant.

The first concept you should be aware of is the decorator class. A decorator is a simple class that is designed to decorate the log entries you send to it. For example, you can make an HTML decorator, which will take log entries and add HTML codes to them.

NOTE

In a game, whenever you have an error, you can log the message as "ERROR: blah blah blah"; and if your decorator class supports a colored format like HTML, it can search for that string and add red coloring to it, indicating that the string should stand out in the log file. Or if you're boring, you can just use a plain text decorator, such as the one I've provided for you.

Decorators

The decorator classes should have four functions: FileHeader() , Decorate() , SessionOpen() , and SessionClose() . All functions should return an std::string . The FileHeader() function returns a string representing the header of the file, such as an HTML header with the title, and so on. The Decorate() function takes a piece of text and decorates it according to the decorator rules. The SessionOpen() and SessionClose() functions return strings representing the beginning and ending of a single session. This would be great for keeping each session in a HTML table, or something similar.

Anyway, here's a simple plain-text decorator class I whipped up for you:

 class TextDecorator { public:     static std::string FileHeader( const std::string& p_title ) {         return "==================================================\n" +                p_title + "\n" +                "==================================================\n\n";     }     static std::string SessionOpen() {         return "\n";     }     static std::string SessionClose() {         return "\n";     }     static std::string Decorate( const std::string& p_string ) {         return p_string + "\n";     } }; 

As you can see, this decorator class is simple. It prints out a simple header, and then prints out newlines for the session openings and closings.

Furthermore, a newline character is added to each entry you want to decorate, because it is assumed that you didn't put those in yourself. As I said, it's pretty simple.

The Logger

The logger is also pretty simple; it has only three functions: a constructor, a destructor, and a Log() function. It also has three data members : a file stream and two Booleans, which determine if the log should be time- and date-stamped. Here's the class definition:

 template<class decorator> class Logger { public:     Logger( const std::string& p_filename,             const std::string& p_logtitle,             bool p_timestamp = false,             bool p_datestamp = false );     ~Logger();     void Log( const std::string& p_entry ); protected:     std::fstream m_logfile;     bool m_timestamp;     bool m_datestamp; }; 

The Constructor

The constructor tries to create the file if it doesn't exist, or just open it if it does exist. You set the file name , the title of the log, and the two stamp Booleans as well. Those last two are optional parameters, and they default to false . Here's the function:

 template<class decorator> Logger<decorator>::Logger( const std::string& p_filename,                            const std::string& p_logtitle,                            bool p_timestamp,                            bool p_datestamp ) {     fstream filetester( p_filename.c_str(), std::ios::in );     if( filetester.is_open() ) {         filetester.close();         m_logfile.open( p_filename.c_str(), std::ios::out  std::ios::app );     }     else {         m_logfile.open( p_filename.c_str(), std::ios::out );         m_logfile << decorator::FileHeader( p_logtitle );     }     m_timestamp = true;     m_datestamp = true;     m_logfile << decorator::SessionOpen();     Log( "Session opened." );     m_timestamp = p_timestamp;     m_datestamp = p_datestamp; } 

Since C++ has no easy way to tell if a file exists (sigh), I created a temporary file stream named filetester . This is opened in read-only mode, which means that opening it fails if the file doesn't exist. So the line after that checks to see if the file's open, and if so, the temporary file is closed, and the log file is opened in append mode. That means that the contents of the file remain the same, and all new data is added to the end of the file.

If the file doesn't exist, the log file is still opened, and the decorator class is consulted to get a file header, which is then put into the log file.

The time- and date-stamp Booleans are both set to true , because the session's opening message should always be time- and date-stamped. The decorator class is once again consulted to get text to be written representing an open session, and then the entry Session opened. is logged. Finally, the time- and date-stamp Booleans passed in as parameters are copied from the parameter values.

The Destructor

Whenever a logger is destroyed , the appropriate session-closing text should be written to the file, and the file should be closed:

 template< class decorator > Logger< decorator >::~Logger() {     m_timestamp = true;     m_datestamp = true;     Log( "Session closed." );     m_logfile << decorator::SessionClose(); } 

Once again, the session-closing text should also be time- and date-stamped.

It's Log, LogIt's Big, It's Heavy, It's Wood!

No one remembers that song? Bah!

NOTE

Watch more Ren & Stimpy .

Anyway, here's the Log function, which sends a string of text to your logfile.

 template< class decorator > void Logger< decorator >::Log( const std::string& p_entry ) {     std::string message;     if( m_datestamp ) {         message += "[" + DateStamp() + "] ";     }     if( m_timestamp ) {         message += "[" + TimeStamp() + "] ";     }     message += p_entry;     m_logfile << decorator::Decorate( message ); } 

A string containing the message is created; if the user wants time- or date-stamps, they are added to the message, and the entry is added at the end as well. Finally, the message is sent through the decorator and then added to the file.

Using the Logger

To make things easier for you, I've included a typedef in the logger files:

 typedef Logger<TextDecorator> TextLog; 

Therefore, you don't have to do all kinds of ugly stuff just to use a text decorator with a logger. Here's how you would create one:

 #include "BasicLib/BasicLib.h" BasicLib::TextLog SystemLog( "syslog.txt", "System Log" ); SystemLog.Log( "Log Entry" ); 

After executing this code, I had a file named syslog.txt that looked like this:

 ================================================== System Log ================================================== [2003.05.19] [02:55:03] Session opened. Log Entry [2003.05.19] [02:55:03] Session closed. 

Don't ask why I'm running code demonstrations at 3 A.M.blah. Feel free to create your own decorator classes to make your log files prettier. HTML is a popular format nowadays for logs, so you might want to make an HTML decorator.

[ LiB ]


MUD Game Programming
MUD Game Programming (Premier Press Game Development)
ISBN: 1592000908
EAN: 2147483647
Year: 2003
Pages: 147
Authors: Ron Penton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net