Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/console/src/libraries/util/OutputHandler.cc @ 6007

Last change on this file since 6007 was 6007, checked in by rgrieder, 16 years ago

Fixed IOConsole partly and fixed two problems in PathConfig and OutputHandler

  • Property svn:eol-style set to native
File size: 8.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:
[5994]25 *      Reto Grieder
[1505]26 *
27 */
28
29/**
[5994]30@file
31@brief
32    Definition of classes related to output (logging).
[1505]33*/
34
35#include "OutputHandler.h"
36
[5994]37#include <algorithm>
[2710]38#include <ctime>
39#include <cstdlib>
[5994]40#include <fstream>
41#include <sstream>
[2710]42
[5994]43#include "Debug.h"
44
[1505]45namespace orxonox
46{
[5994]47    //! How the log file shall be named on the filesystem
48    const std::string logFileBaseName_g = "orxonox.log";
49
50    /////////////////////////
51    ///// LogFileWriter /////
52    /////////////////////////
[1505]53    /**
[5994]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.
[1505]61    */
[5994]62    class LogFileWriter : public OutputListener
[1505]63    {
[5994]64    public:
[6000]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        */
[6007]72        LogFileWriter()
[5994]73            : OutputListener(OutputHandler::logFileOutputListenerName_s)
74        {
75            // Get path for a temporary file
[2710]76#ifdef ORXONOX_PLATFORM_WINDOWS
[5994]77            char* pTempDir = getenv("TEMP");
78            this->logFilename_ = std::string(pTempDir) + "/" + logFileBaseName_g;
[2710]79#else
[5994]80            this->logFilename_ = std::string("/tmp/") + logFileBaseName_g;
[2710]81#endif
82
[5994]83            // Get current time
84            time_t rawtime;
85            struct tm* timeinfo;
86            time(&rawtime);
87            timeinfo = localtime(&rawtime);
[2087]88
[5994]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();
[2087]92
[5994]93            this->outputStream_ = &this->logFile_;
94        }
[1505]95
[5994]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    ///// MemoryLogWriter /////
125    ///////////////////////////
[1505]126    /**
[5994]127    @brief
128        OutputListener that writes all the output piece by piece to an array
129        associated with the corresponding output level.
130    @note
131        Only output below or equal to the current soft debug level is written
132        to minimise huge arrays for the normal run.
[1505]133    */
[5994]134    class MemoryLogWriter : public OutputListener
[1505]135    {
[5994]136    public:
137        friend class OutputHandler;
[1505]138
[6000]139        /**
140        @brief
141            Sets the right soft debug level and registers itself
142        @param outputHandler
143            This is only required to avoid another call to getInstance (this c'tor was
144            called from getInstance!)
145        */
[6007]146        MemoryLogWriter()
[5994]147            : OutputListener("memoryLog")
148        {
149            this->outputStream_ = &this->buffer_;
150        }
151
152        //! Pushed the just written output to the internal array
[6004]153        void outputChanged(int level)
[5994]154        {
155            // Read ostringstream and store it
[6004]156            this->output_.push_back(std::make_pair(level, this->buffer_.str()));
[5994]157            // Clear content and flags
158            this->buffer_.str(std::string());
159            this->buffer_.clear();
160        }
161
162    private:
163        std::ostringstream                        buffer_; //! Stream object used to process the output
164        std::vector<std::pair<int, std::string> > output_; //! Vector containing ALL output
165    };
166
167
168    /////////////////////////
169    ///// OutputHandler /////
170    /////////////////////////
171    const std::string OutputHandler::logFileOutputListenerName_s = "logFile";
172          int         OutputHandler::softDebugLevel_s = hardDebugLevel;
173
174    //! Creates the LogFileWriter and the MemoryLogWriter
175    OutputHandler::OutputHandler()
176        : outputLevel_(OutputLevel::Verbose)
[1505]177    {
[6007]178        this->logFile_ = new LogFileWriter();
179        // Use default level until we get the configValue from the Core
180        this->logFile_->softDebugLevel_ = OutputLevel::Debug;
181        this->registerOutputListener(this->logFile_);
182
183        this->output_  = new MemoryLogWriter();
184        // We capture as much input as the listener with the highest level
185        this->output_->softDebugLevel_ = getSoftDebugLevel();
186        this->registerOutputListener(this->output_);
[1505]187    }
188
[5994]189    //! Destroys the LogFileWriter and the MemoryLogWriter
190    OutputHandler::~OutputHandler()
[1586]191    {
[5994]192        delete this->logFile_;
193        delete this->output_;
[1586]194    }
195
[5994]196    OutputHandler& OutputHandler::getInstance()
[1505]197    {
[5994]198        static OutputHandler orxout;
199        return orxout;
[1505]200    }
201
[5994]202    void OutputHandler::registerOutputListener(OutputListener* listener)
[1505]203    {
[5994]204        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[2662]205        {
[5994]206            if ((*it)->name_ == listener->name_)
207            {
208                COUT(2) << "OutputHandler, Warning: Trying to register two listeners with the same name!" << std::endl;
209                return;
210            }
[2662]211        }
[5994]212        this->listeners_.push_back(listener);
[6004]213        // Update global soft debug level
214        this->setSoftDebugLevel(listener->getOutputListenerName(), listener->getSoftDebugLevel());
[1505]215    }
216
[5994]217    void OutputHandler::unregisterOutputListener(OutputListener* listener)
218    {
219        this->listeners_.remove(listener);
220    }
221
[2710]222    void OutputHandler::setLogPath(const std::string& path)
223    {
[5994]224        this->logFile_->setLogPath(path);
[2710]225    }
226
[5994]227    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const
[1505]228    {
[5994]229        return this->output_->output_.begin();
[1505]230    }
231
[5994]232    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const
[1505]233    {
[5994]234        return this->output_->output_.end();
[1505]235    }
236
[5994]237    int OutputHandler::getSoftDebugLevel(const std::string& name) const
[1505]238    {
[5994]239        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[1505]240        {
[5994]241            if ((*it)->name_ == name)
242                return (*it)->softDebugLevel_;
[1505]243        }
[5994]244        return -1;
[1505]245    }
246
[5994]247    void OutputHandler::setSoftDebugLevel(const std::string& name, int level)
[1505]248    {
[5994]249        int globalSoftDebugLevel = -1;
250        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
[1505]251        {
[5994]252            if ((*it)->name_ == name)
253                (*it)->softDebugLevel_ = level;
254            if ((*it)->softDebugLevel_ > globalSoftDebugLevel)
255                globalSoftDebugLevel = (*it)->softDebugLevel_;
[1505]256        }
[5994]257        // Update global soft debug level
258        OutputHandler::softDebugLevel_s = globalSoftDebugLevel;
[1505]259    }
260}
Note: See TracBrowser for help on using the repository browser.