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