Changeset 6105 for code/trunk/src/libraries/util/OutputHandler.cc
- Timestamp:
- Nov 20, 2009, 4:55:40 PM (14 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
/code/branches/console (added) merged: 5941,5945,5968-5975,5983,5985-5986,5991-5992,5994-5996,5998,6000,6004-6007,6010-6017,6034,6037,6041,6043-6044,6089,6103-6104
- Property svn:mergeinfo changed
-
code/trunk/src/libraries/util/OutputHandler.cc
r5738 r6105 23 23 * Fabian 'x3n' Landau 24 24 * Co-authors: 25 * ...25 * Reto Grieder 26 26 * 27 27 */ 28 28 29 29 /** 30 @file 31 @brief Implementation of the OutputHandler class. 30 @file 31 @brief 32 Definition of classes related to output (logging). 32 33 */ 33 34 34 35 #include "OutputHandler.h" 35 36 37 #include <algorithm> 36 38 #include <ctime> 37 39 #include <cstdlib> 40 #include <fstream> 41 #include <sstream> 42 43 #include "Debug.h" 38 44 39 45 namespace orxonox 40 46 { 47 //! How the log file shall be named on the filesystem 48 const std::string logFileBaseName_g = "orxonox.log"; 49 50 ///////////////////////// 51 ///// LogFileWriter ///// 52 ///////////////////////// 41 53 /** 42 @brief Constructor: Opens the logfile and writes the first line. 43 @param logfilename The name of the logfile 54 @brief 55 Writes the output to the log file. 56 @note 57 As long as the correct log path is not yet known (for pre main code), the 58 LogFileWriter will write to a temporary file in /temp (Unix) or %TEMP% (Windows). 59 As soon as you set the correct path setLogPath the content of the temporary file 60 is read and put into the new file as well. 44 61 */ 62 class LogFileWriter : public OutputListener 63 { 64 public: 65 /** 66 @brief 67 Gets temporary log path and starts the log file 68 @param outputHandler 69 This is only required to avoid another call to getInstance (this c'tor was 70 called from getInstance!) 71 */ 72 LogFileWriter() 73 : OutputListener(OutputHandler::logFileOutputListenerName_s) 74 { 75 // Get path for a temporary file 76 #ifdef ORXONOX_PLATFORM_WINDOWS 77 char* pTempDir = getenv("TEMP"); 78 this->logFilename_ = std::string(pTempDir) + "/" + logFileBaseName_g; 79 #else 80 this->logFilename_ = std::string("/tmp/") + logFileBaseName_g; 81 #endif 82 83 // Get current time 84 time_t rawtime; 85 struct tm* timeinfo; 86 time(&rawtime); 87 timeinfo = localtime(&rawtime); 88 89 this->logFile_.open(this->logFilename_.c_str(), std::fstream::out); 90 this->logFile_ << "Started log on " << asctime(timeinfo) << std::endl; 91 this->logFile_.flush(); 92 93 this->outputStream_ = &this->logFile_; 94 } 95 96 //! Closes the log file 97 ~LogFileWriter() 98 { 99 this->logFile_ << "Closed log" << std::endl; 100 this->logFile_.close(); 101 } 102 103 //! Changes the log path 104 void setLogPath(const std::string& path) 105 { 106 this->logFile_.close(); 107 // Read old file into a buffer 108 std::ifstream old(this->logFilename_.c_str()); 109 this->logFilename_ = path + logFileBaseName_g; 110 // Open the new file and feed it the content of the old one 111 this->logFile_.open(this->logFilename_.c_str(), std::fstream::out); 112 this->logFile_ << old.rdbuf(); 113 this->logFile_.flush(); 114 old.close(); 115 } 116 117 private: 118 std::ofstream logFile_; //! File handle for the log file 119 std::string logFilename_; //! Filename of the log file 120 }; 121 122 123 ///////////////////////// 124 ///// ConsoleWriter ///// 125 ///////////////////////// 126 /** 127 @brief 128 Writes the output to std::cout. 129 @note 130 This listener will usually be disable once an actual shell with console is instantiated. 131 */ 132 class ConsoleWriter : public OutputListener 133 { 134 public: 135 //! Only assigns the output stream with std::cout 136 ConsoleWriter() 137 : OutputListener("consoleLog") 138 { 139 this->outputStream_ = &std::cout; 140 } 141 }; 142 143 144 /////////////////////////// 145 ///// MemoryLogWriter ///// 146 /////////////////////////// 147 /** 148 @brief 149 OutputListener that writes all the output piece by piece to an array 150 associated with the corresponding output level. 151 @note 152 Only output below or equal to the current soft debug level is written 153 to minimise huge arrays for the normal run. 154 */ 155 class MemoryLogWriter : public OutputListener 156 { 157 public: 158 friend class OutputHandler; 159 160 /** 161 @brief 162 Sets the right soft debug level and registers itself 163 @param outputHandler 164 This is only required to avoid another call to getInstance (this c'tor was 165 called from getInstance!) 166 */ 167 MemoryLogWriter() 168 : OutputListener("memoryLog") 169 { 170 this->outputStream_ = &this->buffer_; 171 } 172 173 //! Pushed the just written output to the internal array 174 void outputChanged(int level) 175 { 176 // Read ostringstream and store it 177 this->output_.push_back(std::make_pair(level, this->buffer_.str())); 178 // Clear content and flags 179 this->buffer_.str(std::string()); 180 this->buffer_.clear(); 181 } 182 183 private: 184 std::ostringstream buffer_; //! Stream object used to process the output 185 std::vector<std::pair<int, std::string> > output_; //! Vector containing ALL output 186 }; 187 188 189 ///////////////////////// 190 ///// OutputHandler ///// 191 ///////////////////////// 192 const std::string OutputHandler::logFileOutputListenerName_s = "logFile"; 193 int OutputHandler::softDebugLevel_s = hardDebugLevel; 194 195 //! Creates the LogFileWriter and the MemoryLogWriter 45 196 OutputHandler::OutputHandler() 46 { 47 #ifdef ORXONOX_PLATFORM_WINDOWS 48 char* pTempDir = getenv("TEMP"); 49 this->logfilename_ = std::string(pTempDir) + "/orxonox.log"; 197 : outputLevel_(OutputLevel::Verbose) 198 { 199 #ifdef ORXONOX_RELEASE 200 const OutputLevel::Value defaultLevelConsole = OutputLevel::Error; 201 const OutputLevel::Value defaultLevelLogFile = OutputLevel::Info; 50 202 #else 51 this->logfilename_ = "/tmp/orxonox.log"; 203 const OutputLevel::Value defaultLevelConsole = OutputLevel::Info; 204 const OutputLevel::Value defaultLevelLogFile = OutputLevel::Debug; 52 205 #endif 53 #ifdef NDEBUG 54 this->softDebugLevel_[LD_All] = this->softDebugLevel_[LD_Logfile] = 2; 55 this->softDebugLevel_[LD_Console] = this->softDebugLevel_[LD_Shell] = 1; 56 #else 57 this->softDebugLevel_[LD_All] = this->softDebugLevel_[LD_Logfile] = 3; 58 this->softDebugLevel_[LD_Console] = this->softDebugLevel_[LD_Shell] = 2; 59 #endif 60 61 this->outputBuffer_ = &this->fallbackBuffer_; 62 this->logfile_.open(this->logfilename_.c_str(), std::fstream::out); 63 64 time_t rawtime; 65 struct tm* timeinfo; 66 time(&rawtime); 67 timeinfo = localtime(&rawtime); 68 69 this->logfile_ << "Started log on " << asctime(timeinfo) << std::endl; 70 this->logfile_.flush(); 71 } 72 73 /** 74 @brief Destructor: Writes the last line to the logfile and closes it. 75 */ 206 207 this->logFile_ = new LogFileWriter(); 208 // Use default level until we get the configValue from the Core 209 this->logFile_->softDebugLevel_ = defaultLevelLogFile; 210 this->registerOutputListener(this->logFile_); 211 212 this->consoleWriter_ = new ConsoleWriter(); 213 this->consoleWriter_->softDebugLevel_ = defaultLevelConsole; 214 this->registerOutputListener(this->consoleWriter_); 215 216 this->output_ = new MemoryLogWriter(); 217 // We capture as much input as the listener with the highest level 218 this->output_->softDebugLevel_ = getSoftDebugLevel(); 219 this->registerOutputListener(this->output_); 220 } 221 222 //! Destroys the LogFileWriter and the MemoryLogWriter 76 223 OutputHandler::~OutputHandler() 77 224 { 78 this->logfile_ << "Closed log" << std::endl; 79 this->logfile_.close(); 80 } 81 82 /** 83 @brief Returns a reference to the only existing instance of the OutputHandler class. 84 @return The instance 85 */ 86 OutputHandler& OutputHandler::getOutStream() 225 delete this->logFile_; 226 delete this->output_; 227 } 228 229 OutputHandler& OutputHandler::getInstance() 87 230 { 88 231 static OutputHandler orxout; … … 90 233 } 91 234 92 /** 93 @brief Sets the soft debug level for a given output device. 94 @param device The output device 95 @param level The debug level 96 */ 97 void OutputHandler::setSoftDebugLevel(OutputHandler::OutputDevice device, int level) 98 { 99 OutputHandler::getOutStream().softDebugLevel_[static_cast<unsigned int>(device)] = level; 100 } 101 102 /** 103 @brief Returns the soft debug level for a given output device. 104 @param device The output device 105 @return The debug level 106 */ 107 int OutputHandler::getSoftDebugLevel(OutputHandler::OutputDevice device) 108 { 109 return OutputHandler::getOutStream().softDebugLevel_[static_cast<unsigned int>(device)]; 110 } 111 112 /** 113 @brief Sets the OutputBuffer, representing the third output stream. 114 @param buffer The OutputBuffer 115 */ 116 void OutputHandler::setOutputBuffer(OutputBuffer* buffer) 117 { 118 if (buffer == NULL) 119 this->outputBuffer_ = &this->fallbackBuffer_; 120 else 121 { 122 buffer->getStream() >> this->outputBuffer_->getStream().rdbuf(); 123 this->outputBuffer_ = buffer; 124 } 125 } 126 127 /** 128 @brief Sets the path where to create orxonox.log 129 @param Path string with trailing slash 130 */ 235 void OutputHandler::registerOutputListener(OutputListener* listener) 236 { 237 for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it) 238 { 239 if ((*it)->name_ == listener->name_) 240 { 241 COUT(2) << "OutputHandler, Warning: Trying to register two listeners with the same name!" << std::endl; 242 return; 243 } 244 } 245 this->listeners_.push_back(listener); 246 // Update global soft debug level 247 this->setSoftDebugLevel(listener->getOutputListenerName(), listener->getSoftDebugLevel()); 248 } 249 250 void OutputHandler::unregisterOutputListener(OutputListener* listener) 251 { 252 this->listeners_.remove(listener); 253 } 254 131 255 void OutputHandler::setLogPath(const std::string& path) 132 256 { 133 OutputHandler::getOutStream().logfile_.close(); 134 // store old content 135 std::ifstream old; 136 old.open(OutputHandler::getOutStream().logfilename_.c_str()); 137 OutputHandler::getOutStream().logfilename_ = path + "orxonox.log"; 138 OutputHandler::getOutStream().logfile_.open(OutputHandler::getOutStream().logfilename_.c_str(), std::fstream::out); 139 OutputHandler::getOutStream().logfile_ << old.rdbuf(); 140 old.close(); 141 OutputHandler::getOutStream().logfile_.flush(); 142 } 143 144 /** 145 @brief Overloaded << operator, redirects the output to the console and the logfile. 146 @param sb The streambuffer that should be shown in the console 147 @return A reference to the OutputHandler itself 148 */ 149 OutputHandler& OutputHandler::operator<<(std::streambuf* sb) 150 { 151 if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_) 152 std::cout << sb; 153 154 if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_) 155 { 156 this->logfile_ << sb; 157 this->logfile_.flush(); 158 } 159 160 if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_) 161 (*this->outputBuffer_) << sb; 162 163 return *this; 164 } 165 166 /** 167 @brief Overloaded << operator, redirects the output to the console, the logfile and the ingame shell. 168 @param manipulator A function, manipulating the outstream. 169 @return A reference to the OutputHandler itself 170 */ 171 OutputHandler& OutputHandler::operator<<(std::ostream& (*manipulator)(std::ostream&)) 172 { 173 if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_) 174 manipulator(std::cout); 175 176 if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_) 177 { 178 manipulator(this->logfile_); 179 this->logfile_.flush(); 180 } 181 182 if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_) 183 (*this->outputBuffer_) << manipulator; 184 185 return *this; 186 } 187 188 /** 189 @brief Overloaded << operator, redirects the output to the console, the logfile and the ingame shell. 190 @param manipulator A function, manipulating the outstream. 191 @return A reference to the OutputHandler itself 192 */ 193 OutputHandler& OutputHandler::operator<<(std::ios& (*manipulator)(std::ios&)) 194 { 195 if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_) 196 manipulator(std::cout); 197 198 if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_) 199 { 200 manipulator(this->logfile_); 201 this->logfile_.flush(); 202 } 203 204 if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_) 205 (*this->outputBuffer_) << manipulator; 206 207 return *this; 208 } 209 210 /** 211 @brief Overloaded << operator, redirects the output to the console, the logfile and the ingame shell. 212 @param manipulator A function, manipulating the outstream. 213 @return A reference to the OutputHandler itself 214 */ 215 OutputHandler& OutputHandler::operator<<(std::ios_base& (*manipulator)(std::ios_base&)) 216 { 217 if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_) 218 manipulator(std::cout); 219 220 if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_) 221 { 222 manipulator(this->logfile_); 223 this->logfile_.flush(); 224 } 225 226 if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_) 227 (*this->outputBuffer_) << manipulator; 228 229 return *this; 257 this->logFile_->setLogPath(path); 258 } 259 260 void OutputHandler::disableCout() 261 { 262 this->unregisterOutputListener(this->consoleWriter_); 263 } 264 265 void OutputHandler::enableCout() 266 { 267 this->registerOutputListener(this->consoleWriter_); 268 } 269 270 OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const 271 { 272 return this->output_->output_.begin(); 273 } 274 275 OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const 276 { 277 return this->output_->output_.end(); 278 } 279 280 int OutputHandler::getSoftDebugLevel(const std::string& name) const 281 { 282 for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it) 283 { 284 if ((*it)->name_ == name) 285 return (*it)->softDebugLevel_; 286 } 287 return -1; 288 } 289 290 void OutputHandler::setSoftDebugLevel(const std::string& name, int level) 291 { 292 int globalSoftDebugLevel = -1; 293 for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it) 294 { 295 if ((*it)->name_ == name) 296 (*it)->softDebugLevel_ = level; 297 if ((*it)->softDebugLevel_ > globalSoftDebugLevel) 298 globalSoftDebugLevel = (*it)->softDebugLevel_; 299 } 300 // Update global soft debug level 301 OutputHandler::softDebugLevel_s = globalSoftDebugLevel; 230 302 } 231 303 }
Note: See TracChangeset
for help on using the changeset viewer.