Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/OutputHandler.cc @ 8486

Last change on this file since 8486 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

  • Property svn:eol-style set to native
File size: 9.4 KB
RevLine 
[1505]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
[6105]25 *      Reto Grieder
[1505]26 *
27 */
28
29/**
[6105]30@file
31@brief
32    Definition of classes related to output (logging).
[1505]33*/
34
35#include "OutputHandler.h"
36
[6105]37#include <algorithm>
[2710]38#include <ctime>
39#include <cstdlib>
[6105]40#include <fstream>
[6417]41#include <iostream>
[6105]42#include <sstream>
[2710]43
[6105]44#include "Debug.h"
45
[1505]46namespace orxonox
47{
[6105]48    //! How the log file shall be named on the filesystem
49    const std::string logFileBaseName_g = "orxonox.log";
50
51    /////////////////////////
52    ///// LogFileWriter /////
53    /////////////////////////
[1505]54    /**
[6105]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.
[1505]62    */
[6105]63    class LogFileWriter : public OutputListener
[1505]64    {
[6105]65    public:
66        /**
67        @brief
68            Gets temporary log path and starts the log file
69        */
70        LogFileWriter()
71            : OutputListener(OutputHandler::logFileOutputListenerName_s)
72        {
73            // Get path for a temporary file
[2710]74#ifdef ORXONOX_PLATFORM_WINDOWS
[6105]75            char* pTempDir = getenv("TEMP");
[6417]76            this->logFilename_ = std::string(pTempDir) + '/' + logFileBaseName_g;
[2710]77#else
[6105]78            this->logFilename_ = std::string("/tmp/") + logFileBaseName_g;
[2710]79#endif
80
[6105]81            // Get current time
82            time_t rawtime;
83            struct tm* timeinfo;
84            time(&rawtime);
85            timeinfo = localtime(&rawtime);
[2087]86
[6105]87            this->logFile_.open(this->logFilename_.c_str(), std::fstream::out);
88            this->logFile_ << "Started log on " << asctime(timeinfo) << std::endl;
89            this->logFile_.flush();
[2087]90
[6105]91            this->outputStream_ = &this->logFile_;
92        }
[1505]93
[6105]94        //! Closes the log file
95        ~LogFileWriter()
96        {
97            this->logFile_ << "Closed log" << std::endl;
98            this->logFile_.close();
99        }
100
101        //! Changes the log path
102        void setLogPath(const std::string& path)
103        {
104            this->logFile_.close();
105            // Read old file into a buffer
106            std::ifstream old(this->logFilename_.c_str());
107            this->logFilename_ = path + logFileBaseName_g;
108            // Open the new file and feed it the content of the old one
109            this->logFile_.open(this->logFilename_.c_str(), std::fstream::out);
110            this->logFile_ << old.rdbuf();
111            this->logFile_.flush();
112            old.close();
113        }
114
115    private:
[7401]116        std::ofstream logFile_;     //!< File handle for the log file
117        std::string   logFilename_; //!< Filename of the log file
[6105]118    };
119
120
121    /////////////////////////
122    ///// ConsoleWriter /////
123    /////////////////////////
[1505]124    /**
[6105]125    @brief
126        Writes the output to std::cout.
127    @note
128        This listener will usually be disable once an actual shell with console is instantiated.
[1505]129    */
[6105]130    class ConsoleWriter : public OutputListener
[1505]131    {
[6105]132    public:
133        //! Only assigns the output stream with std::cout
134        ConsoleWriter()
135            : OutputListener("consoleLog")
136        {
137            this->outputStream_ = &std::cout;
138        }
139    };
[1505]140
[6105]141
142    ///////////////////////////
143    ///// MemoryLogWriter /////
144    ///////////////////////////
[1505]145    /**
[6105]146    @brief
147        OutputListener that writes all the output piece by piece to an array
148        associated with the corresponding output level.
149    @note
150        Only output below or equal to the current soft debug level is written
151        to minimise huge arrays for the normal run.
[1505]152    */
[6105]153    class MemoryLogWriter : public OutputListener
[1505]154    {
[6105]155    public:
156        friend class OutputHandler;
157
158        /**
159        @brief
160            Sets the right soft debug level and registers itself
161        */
162        MemoryLogWriter()
163            : OutputListener("memoryLog")
164        {
165            this->outputStream_ = &this->buffer_;
166        }
167
168        //! Pushed the just written output to the internal array
169        void outputChanged(int level)
170        {
[6417]171            if (!this->buffer_.str().empty())
172            {
173                // Read ostringstream and store it
174                this->output_.push_back(std::make_pair(level, this->buffer_.str()));
175                // Clear content and flags
176                this->buffer_.str(std::string());
177            }
[6105]178            this->buffer_.clear();
179        }
180
181    private:
[7401]182        std::ostringstream                        buffer_; //!< Stream object used to process the output
183        std::vector<std::pair<int, std::string> > output_; //!< Vector containing ALL output
[6105]184    };
185
186
187    /////////////////////////
188    ///// OutputHandler /////
189    /////////////////////////
190    const std::string OutputHandler::logFileOutputListenerName_s = "logFile";
191          int         OutputHandler::softDebugLevel_s = hardDebugLevel;
192
193    //! Creates the LogFileWriter and the MemoryLogWriter
194    OutputHandler::OutputHandler()
195        : outputLevel_(OutputLevel::Verbose)
196    {
197#ifdef ORXONOX_RELEASE
198        const OutputLevel::Value defaultLevelConsole = OutputLevel::Error;
199        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Info;
200#else
201        const OutputLevel::Value defaultLevelConsole = OutputLevel::Info;
202        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Debug;
203#endif
204
205        this->logFile_ = new LogFileWriter();
206        // Use default level until we get the configValue from the Core
207        this->logFile_->softDebugLevel_ = defaultLevelLogFile;
208        this->registerOutputListener(this->logFile_);
209
210        this->consoleWriter_ = new ConsoleWriter();
211        this->consoleWriter_->softDebugLevel_ = defaultLevelConsole;
212        this->registerOutputListener(this->consoleWriter_);
213
[6417]214        this->output_ = new MemoryLogWriter();
[6105]215        // We capture as much input as the listener with the highest level
216        this->output_->softDebugLevel_ = getSoftDebugLevel();
217        this->registerOutputListener(this->output_);
[1505]218    }
219
[6105]220    //! Destroys the LogFileWriter and the MemoryLogWriter
221    OutputHandler::~OutputHandler()
[1586]222    {
[6105]223        delete this->logFile_;
[6417]224        delete this->consoleWriter_;
[6105]225        delete this->output_;
[1586]226    }
227
[6105]228    OutputHandler& OutputHandler::getInstance()
[1505]229    {
[6105]230        static OutputHandler orxout;
231        return orxout;
[1505]232    }
233
[6105]234    void OutputHandler::registerOutputListener(OutputListener* listener)
[1505]235    {
[6105]236        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[2662]237        {
[6105]238            if ((*it)->name_ == listener->name_)
239            {
240                COUT(2) << "OutputHandler, Warning: Trying to register two listeners with the same name!" << std::endl;
241                return;
242            }
[2662]243        }
[6105]244        this->listeners_.push_back(listener);
245        // Update global soft debug level
246        this->setSoftDebugLevel(listener->getOutputListenerName(), listener->getSoftDebugLevel());
[1505]247    }
248
[6105]249    void OutputHandler::unregisterOutputListener(OutputListener* listener)
250    {
251        this->listeners_.remove(listener);
252    }
253
[2710]254    void OutputHandler::setLogPath(const std::string& path)
255    {
[6105]256        this->logFile_->setLogPath(path);
[2710]257    }
258
[6105]259    void OutputHandler::disableCout()
[1505]260    {
[6105]261        this->unregisterOutputListener(this->consoleWriter_);
262    }
[1505]263
[6105]264    void OutputHandler::enableCout()
265    {
266        this->registerOutputListener(this->consoleWriter_);
267    }
[1505]268
[6105]269    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const
270    {
271        return this->output_->output_.begin();
[1505]272    }
273
[6105]274    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const
[1505]275    {
[6105]276        return this->output_->output_.end();
[1505]277    }
278
[6105]279    int OutputHandler::getSoftDebugLevel(const std::string& name) const
[1505]280    {
[6105]281        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[1505]282        {
[6105]283            if ((*it)->name_ == name)
284                return (*it)->softDebugLevel_;
[1505]285        }
[6105]286        return -1;
[1505]287    }
288
[6105]289    void OutputHandler::setSoftDebugLevel(const std::string& name, int level)
[1505]290    {
[6105]291        int globalSoftDebugLevel = -1;
292        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[1505]293        {
[6105]294            if ((*it)->name_ == name)
295                (*it)->softDebugLevel_ = level;
296            if ((*it)->softDebugLevel_ > globalSoftDebugLevel)
297                globalSoftDebugLevel = (*it)->softDebugLevel_;
[1505]298        }
[6105]299        // Update global soft debug level
300        OutputHandler::softDebugLevel_s = globalSoftDebugLevel;
[1505]301    }
302}
Note: See TracBrowser for help on using the repository browser.