- Timestamp:
- Oct 27, 2009, 2:47:14 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/console/src/libraries/util/OutputHandler.cc
r5983 r5994 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 //! Gets temporary log path and starts the log file 66 LogFileWriter() 67 : OutputListener(OutputHandler::logFileOutputListenerName_s) 68 { 69 // Get path for a temporary file 70 #ifdef ORXONOX_PLATFORM_WINDOWS 71 char* pTempDir = getenv("TEMP"); 72 this->logFilename_ = std::string(pTempDir) + "/" + logFileBaseName_g; 73 #else 74 this->logFilename_ = std::string("/tmp/") + logFileBaseName_g; 75 #endif 76 77 // Get current time 78 time_t rawtime; 79 struct tm* timeinfo; 80 time(&rawtime); 81 timeinfo = localtime(&rawtime); 82 83 this->logFile_.open(this->logFilename_.c_str(), std::fstream::out); 84 this->logFile_ << "Started log on " << asctime(timeinfo) << std::endl; 85 this->logFile_.flush(); 86 87 this->outputStream_ = &this->logFile_; 88 // Use default level until we get the configValue from the Core 89 OutputHandler::getInstance().setSoftDebugLevel(this->getOutputListenerName(), OutputLevel::Debug); 90 OutputHandler::getInstance().registerOutputListener(this); 91 } 92 93 //! Closes the log file 94 ~LogFileWriter() 95 { 96 this->logFile_ << "Closed log" << std::endl; 97 this->logFile_.close(); 98 } 99 100 //! Changes the log path 101 void setLogPath(const std::string& path) 102 { 103 this->logFile_.close(); 104 // Read old file into a buffer 105 std::ifstream old(this->logFilename_.c_str()); 106 this->logFilename_ = path + logFileBaseName_g; 107 // Open the new file and feed it the content of the old one 108 this->logFile_.open(this->logFilename_.c_str(), std::fstream::out); 109 this->logFile_ << old.rdbuf(); 110 this->logFile_.flush(); 111 old.close(); 112 } 113 114 private: 115 std::ofstream logFile_; //! File handle for the log file 116 std::string logFilename_; //! Filename of the log file 117 }; 118 119 120 /////////////////////////// 121 ///// MemoryLogWriter ///// 122 /////////////////////////// 123 /** 124 @brief 125 OutputListener that writes all the output piece by piece to an array 126 associated with the corresponding output level. 127 @note 128 Only output below or equal to the current soft debug level is written 129 to minimise huge arrays for the normal run. 130 */ 131 class MemoryLogWriter : public OutputListener 132 { 133 public: 134 friend class OutputHandler; 135 136 //! Sets the right soft debug level and registers itself 137 MemoryLogWriter() 138 : OutputListener("memoryLog") 139 { 140 this->outputStream_ = &this->buffer_; 141 // We capture as much input as the listener with the highest level 142 OutputHandler::getInstance().setSoftDebugLevel(this->getOutputListenerName(), OutputHandler::getSoftDebugLevel()); 143 OutputHandler::getInstance().registerOutputListener(this); 144 } 145 146 //! Pushed the just written output to the internal array 147 void outputChanged() 148 { 149 // Read ostringstream and store it 150 this->output_.push_back(std::make_pair(OutputHandler::getInstance().getOutputLevel(), this->buffer_.str())); 151 // Clear content and flags 152 this->buffer_.str(std::string()); 153 this->buffer_.clear(); 154 } 155 156 private: 157 std::ostringstream buffer_; //! Stream object used to process the output 158 std::vector<std::pair<int, std::string> > output_; //! Vector containing ALL output 159 }; 160 161 162 ///////////////////////// 163 ///// OutputHandler ///// 164 ///////////////////////// 165 const std::string OutputHandler::logFileOutputListenerName_s = "logFile"; 166 int OutputHandler::softDebugLevel_s = hardDebugLevel; 167 168 //! Creates the LogFileWriter and the MemoryLogWriter 45 169 OutputHandler::OutputHandler() 46 { 47 #ifdef ORXONOX_PLATFORM_WINDOWS 48 char* pTempDir = getenv("TEMP"); 49 this->logfilename_ = std::string(pTempDir) + "/orxonox.log"; 50 #else 51 this->logfilename_ = "/tmp/orxonox.log"; 52 #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 */ 170 : outputLevel_(OutputLevel::Verbose) 171 { 172 this->logFile_ = new LogFileWriter(); 173 this->output_ = new MemoryLogWriter(); 174 } 175 176 //! Destroys the LogFileWriter and the MemoryLogWriter 76 177 OutputHandler::~OutputHandler() 77 178 { 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() 179 delete this->logFile_; 180 delete this->output_; 181 } 182 183 OutputHandler& OutputHandler::getInstance() 87 184 { 88 185 static OutputHandler orxout; … … 90 187 } 91 188 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 */ 189 void OutputHandler::registerOutputListener(OutputListener* listener) 190 { 191 for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it) 192 { 193 if ((*it)->name_ == listener->name_) 194 { 195 COUT(2) << "OutputHandler, Warning: Trying to register two listeners with the same name!" << std::endl; 196 return; 197 } 198 } 199 this->listeners_.push_back(listener); 200 } 201 202 void OutputHandler::unregisterOutputListener(OutputListener* listener) 203 { 204 this->listeners_.remove(listener); 205 } 206 131 207 void OutputHandler::setLogPath(const std::string& path) 132 208 { 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; 209 this->logFile_->setLogPath(path); 210 } 211 212 OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const 213 { 214 return this->output_->output_.begin(); 215 } 216 217 OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const 218 { 219 return this->output_->output_.end(); 220 } 221 222 int OutputHandler::getSoftDebugLevel(const std::string& name) const 223 { 224 for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it) 225 { 226 if ((*it)->name_ == name) 227 return (*it)->softDebugLevel_; 228 } 229 return -1; 230 } 231 232 void OutputHandler::setSoftDebugLevel(const std::string& name, int level) 233 { 234 int globalSoftDebugLevel = -1; 235 for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it) 236 { 237 if ((*it)->name_ == name) 238 (*it)->softDebugLevel_ = level; 239 if ((*it)->softDebugLevel_ > globalSoftDebugLevel) 240 globalSoftDebugLevel = (*it)->softDebugLevel_; 241 } 242 // Update global soft debug level 243 OutputHandler::softDebugLevel_s = globalSoftDebugLevel; 230 244 } 231 245 }
Note: See TracChangeset
for help on using the changeset viewer.