Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7171 was 6417, checked in by rgrieder, 15 years ago

Merged presentation2 branch back to trunk.
Major new features:

  • Actual GUI with settings, etc.
  • Improved space ship steering (human interaction)
  • Rocket fire and more particle effects
  • Advanced sound framework
  • Property svn:eol-style set to native
File size: 9.7 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        @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
[2710]77#ifdef ORXONOX_PLATFORM_WINDOWS
[6105]78            char* pTempDir = getenv("TEMP");
[6417]79            this->logFilename_ = std::string(pTempDir) + '/' + logFileBaseName_g;
[2710]80#else
[6105]81            this->logFilename_ = std::string("/tmp/") + logFileBaseName_g;
[2710]82#endif
83
[6105]84            // Get current time
85            time_t rawtime;
86            struct tm* timeinfo;
87            time(&rawtime);
88            timeinfo = localtime(&rawtime);
[2087]89
[6105]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();
[2087]93
[6105]94            this->outputStream_ = &this->logFile_;
95        }
[1505]96
[6105]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    /////////////////////////
[1505]127    /**
[6105]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.
[1505]132    */
[6105]133    class ConsoleWriter : public OutputListener
[1505]134    {
[6105]135    public:
136        //! Only assigns the output stream with std::cout
137        ConsoleWriter()
138            : OutputListener("consoleLog")
139        {
140            this->outputStream_ = &std::cout;
141        }
142    };
[1505]143
[6105]144
145    ///////////////////////////
146    ///// MemoryLogWriter /////
147    ///////////////////////////
[1505]148    /**
[6105]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.
[1505]155    */
[6105]156    class MemoryLogWriter : public OutputListener
[1505]157    {
[6105]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        {
[6417]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            }
[6105]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
200    OutputHandler::OutputHandler()
201        : outputLevel_(OutputLevel::Verbose)
202    {
203#ifdef ORXONOX_RELEASE
204        const OutputLevel::Value defaultLevelConsole = OutputLevel::Error;
205        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Info;
206#else
207        const OutputLevel::Value defaultLevelConsole = OutputLevel::Info;
208        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Debug;
209#endif
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
[6417]220        this->output_ = new MemoryLogWriter();
[6105]221        // We capture as much input as the listener with the highest level
222        this->output_->softDebugLevel_ = getSoftDebugLevel();
223        this->registerOutputListener(this->output_);
[1505]224    }
225
[6105]226    //! Destroys the LogFileWriter and the MemoryLogWriter
227    OutputHandler::~OutputHandler()
[1586]228    {
[6105]229        delete this->logFile_;
[6417]230        delete this->consoleWriter_;
[6105]231        delete this->output_;
[1586]232    }
233
[6105]234    OutputHandler& OutputHandler::getInstance()
[1505]235    {
[6105]236        static OutputHandler orxout;
237        return orxout;
[1505]238    }
239
[6105]240    void OutputHandler::registerOutputListener(OutputListener* listener)
[1505]241    {
[6105]242        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[2662]243        {
[6105]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            }
[2662]249        }
[6105]250        this->listeners_.push_back(listener);
251        // Update global soft debug level
252        this->setSoftDebugLevel(listener->getOutputListenerName(), listener->getSoftDebugLevel());
[1505]253    }
254
[6105]255    void OutputHandler::unregisterOutputListener(OutputListener* listener)
256    {
257        this->listeners_.remove(listener);
258    }
259
[2710]260    void OutputHandler::setLogPath(const std::string& path)
261    {
[6105]262        this->logFile_->setLogPath(path);
[2710]263    }
264
[6105]265    void OutputHandler::disableCout()
[1505]266    {
[6105]267        this->unregisterOutputListener(this->consoleWriter_);
268    }
[1505]269
[6105]270    void OutputHandler::enableCout()
271    {
272        this->registerOutputListener(this->consoleWriter_);
273    }
[1505]274
[6105]275    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const
276    {
277        return this->output_->output_.begin();
[1505]278    }
279
[6105]280    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const
[1505]281    {
[6105]282        return this->output_->output_.end();
[1505]283    }
284
[6105]285    int OutputHandler::getSoftDebugLevel(const std::string& name) const
[1505]286    {
[6105]287        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[1505]288        {
[6105]289            if ((*it)->name_ == name)
290                return (*it)->softDebugLevel_;
[1505]291        }
[6105]292        return -1;
[1505]293    }
294
[6105]295    void OutputHandler::setSoftDebugLevel(const std::string& name, int level)
[1505]296    {
[6105]297        int globalSoftDebugLevel = -1;
298        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[1505]299        {
[6105]300            if ((*it)->name_ == name)
301                (*it)->softDebugLevel_ = level;
302            if ((*it)->softDebugLevel_ > globalSoftDebugLevel)
303                globalSoftDebugLevel = (*it)->softDebugLevel_;
[1505]304        }
[6105]305        // Update global soft debug level
306        OutputHandler::softDebugLevel_s = globalSoftDebugLevel;
[1505]307    }
308}
Note: See TracBrowser for help on using the repository browser.