NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
EventLogger.cpp
Go to the documentation of this file.
00001 
00010 #include "EventLogger.h"
00011 
00012 // Standard Includes
00013 #include <cassert>
00014 #include <fstream>
00015 
00016 // Library Includes
00017 #include <boost/filesystem.hpp>
00018 #include <boost/date_time.hpp>
00019 #include <boost/lexical_cast.hpp>
00020 #include <EngineConfig.h>
00021 
00022 // Local Includes
00023 
00024 // Static class member initialization
00025 EventLogger* EventLogger::glogger(nullptr);
00026 std::string EventLogger::module;
00027 
00028 // Forward declares
00029 void ArchiveOldLog(const std::string&, const std::string& = "", const unsigned int& = 1);
00030 
00031 // Class methods in the order they are defined within the class header
00032 
00033 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00034 EventLogger::EventLogger() {
00035 }
00036 
00037 EventLogger::~EventLogger() {
00038 }
00039 
00040 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00043 void EventLogger::SetEventLogger(EventLogger* elog) {
00044   if (EventLogger::glogger == nullptr) {
00045     EventLogger::glogger = elog;
00046   }
00047 }
00048 
00050 EventLogger* EventLogger::GetEventLogger() {
00051   if (EventLogger::glogger == nullptr) {
00052     EventLogger::SetEventLogger(new EventLogger());
00053   }
00054   
00055   return EventLogger::glogger;
00056 }
00057 
00058 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00059 bool EventLogger::LogToDisk(const LOG_PRIORITY::TYPE& priority_level, const std::string& text, const std::string& file, const unsigned int& line, const std::string& func) {
00060   std::string fname(file);
00061   
00062   if (fname.find_last_of("/") != std::string::npos) {
00063     fname = fname.substr(fname.find_last_of("/") + 1);
00064   }
00065   else if (fname.find_last_of("\\") != std::string::npos) {
00066     fname = fname.substr(fname.find_last_of("\\") + 1);
00067   }
00068   
00069   Threading::WriteLock w_lock(this->mutex);
00070   
00071   // Push the formatted message onto the queue
00072   {
00073     boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
00074     
00075     // Format the log entry: timestamp  priority  module  file(line): function  message
00076     std::stringstream ss;
00077     ss
00078       << boost::posix_time::to_iso_extended_string(now) << "UTC" // Timestamp
00079       << "\t" << LOG_PRIORITY::PRINTABLE_NOTICES[static_cast<unsigned int>(priority_level)] // Error level
00080       << "\t" << EventLogger::module << "|" << fname << "(" << line << "): " << func // Module, file, line, and function in a pattern similar to VS2010's error log.
00081       << "\t" << text // Message
00082       << std::endl;
00083     
00084     // Push into queue
00085     this->logQueue.push(ss.str());
00086   }
00087   
00088   // Write queued messages out to disk, but only if there is a file to send to.
00089   if (this->logFile.length() > 0) {
00090     std::string message;
00091     
00092     std::ofstream out_stream;
00093     
00094     out_stream.open(this->logFile.c_str(), std::ios_base::out | std::ios_base::app);
00095     
00096     if (!out_stream.bad()) {
00097       while (this->logQueue.size() > 0) {
00098         message = this->logQueue.front();
00099         this->logQueue.pop();
00100         
00101         out_stream << message;
00102       }
00103       
00104       out_stream.close();
00105     }
00106     else {
00107       return false; // Return false to indicate the log could not be written to.  Message isn't lost, just stuck in memory!
00108     }
00109   }
00110   
00111   return true;
00112 }
00113 
00114 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00115 bool EventLogger::SetLogFile(const std::string& file) {
00116   Threading::WriteLock w_lock(this->mutex);
00117   
00118   this->logFile = file;
00119   
00120   // If the file exists already, move it to an archived name
00121   ArchiveOldLog(file);
00122   
00123   return true; 
00124 }
00125 
00126 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00127 void ArchiveOldLog(const std::string& old_file, const std::string& new_file, const unsigned int& index) {
00128   std::string base_name;
00129   if (new_file.length()) {
00130     base_name = new_file;
00131   }
00132   else {
00133     base_name = old_file;
00134   }
00135   
00136   std::string file_name(base_name + "." + boost::lexical_cast<std::string>(index));
00137   
00138   if (boost::filesystem::exists(old_file)) {
00139     // If the new file is already in use, go move it to the next slot first.
00140     if(boost::filesystem::exists(file_name)) {
00141       // But limit to 5 archives
00142       if (index < 5) {
00143         ArchiveOldLog(file_name, base_name, index + 1);
00144       }
00145       else {
00146         boost::filesystem::remove_all(file_name);
00147       }
00148     }
00149     
00150     // Rename the passed file into the empty space
00151     boost::filesystem::rename(old_file, file_name);
00152   }
00153 }