Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/unity_build/src/libraries/util/OutputHandler.cc @ 8516

Last change on this file since 8516 was 8516, checked in by rgrieder, 13 years ago

Separate method in OutputHandler for updating the global debug level and using std::vector instead of std::list for the listeners.

  • Property svn:eol-style set to native
File size: 9.8 KB
Line 
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:
25 *      Reto Grieder
26 *
27 */
28
29/**
30@file
31@brief
32    Definition of classes related to output (logging).
33*/
34
35#include "OutputHandler.h"
36
37#include <algorithm>
38#include <ctime>
39#include <cstdlib>
40#include <fstream>
41#include <iostream>
42#include <sstream>
43
44#include "Debug.h"
45
46namespace orxonox
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    /////////////////////////
54    /**
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.
62    */
63    class LogFileWriter : public OutputListener
64    {
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
74#ifdef ORXONOX_PLATFORM_WINDOWS
75            char* pTempDir = getenv("TEMP");
76            this->logFilename_ = std::string(pTempDir) + '/' + logFileBaseName_g;
77#else
78            this->logFilename_ = std::string("/tmp/") + logFileBaseName_g;
79#endif
80
81            // Get current time
82            time_t rawtime;
83            struct tm* timeinfo;
84            time(&rawtime);
85            timeinfo = localtime(&rawtime);
86
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();
90
91            this->outputStream_ = &this->logFile_;
92        }
93
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:
116        std::ofstream logFile_;     //!< File handle for the log file
117        std::string   logFilename_; //!< Filename of the log file
118    };
119
120
121    /////////////////////////
122    ///// ConsoleWriter /////
123    /////////////////////////
124    /**
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.
129    */
130    class ConsoleWriter : public OutputListener
131    {
132    public:
133        //! Only assigns the output stream with std::cout
134        ConsoleWriter()
135            : OutputListener("consoleLog")
136        {
137            this->outputStream_ = &std::cout;
138        }
139    };
140
141
142    ///////////////////////////
143    ///// MemoryLogWriter /////
144    ///////////////////////////
145    /**
146    @brief
147        OutputListener that writes all the output piece by piece to an array
148        associated with the corresponding output level.
149        Used as buffer until all output devices have been initialised.
150    @note
151        At some point, OutputHandler::disableMemoryLog() has to be called in
152        order to avoid large memory footprints of this class.
153    */
154    class MemoryLogWriter : public OutputListener
155    {
156    public:
157        friend class OutputHandler;
158
159        MemoryLogWriter()
160            : OutputListener("memoryLog")
161        {
162            this->outputStream_ = &this->buffer_;
163        }
164
165        //! Push the just written output to the internal array
166        void outputChanged(int level)
167        {
168            if (!this->buffer_.str().empty())
169            {
170                // Read ostringstream and store it
171                this->output_.push_back(std::make_pair(level, this->buffer_.str()));
172                // Clear content and flags
173                this->buffer_.str(std::string());
174            }
175            this->buffer_.clear();
176        }
177
178    private:
179        std::ostringstream          buffer_; //!< Stream object used to process the output
180        OutputHandler::OutputVector output_; //!< Vector containing ALL output
181    };
182
183
184    /////////////////////////
185    ///// OutputHandler /////
186    /////////////////////////
187    const std::string OutputHandler::logFileOutputListenerName_s = "logFile";
188          int         OutputHandler::softDebugLevel_s = hardDebugLevel;
189
190    //! Creates the LogFileWriter and the MemoryLogWriter
191    OutputHandler::OutputHandler()
192        : outputLevel_(OutputLevel::Verbose)
193    {
194#ifdef ORXONOX_RELEASE
195        const OutputLevel::Value defaultLevelConsole = OutputLevel::Error;
196        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Info;
197#else
198        const OutputLevel::Value defaultLevelConsole = OutputLevel::Info;
199        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Debug;
200#endif
201
202        this->logFile_ = new LogFileWriter();
203        // Use default level until we get the configValue from the Core
204        this->logFile_->softDebugLevel_ = defaultLevelLogFile;
205        this->registerOutputListener(this->logFile_);
206
207        this->consoleWriter_ = new ConsoleWriter();
208        this->consoleWriter_->softDebugLevel_ = defaultLevelConsole;
209        this->registerOutputListener(this->consoleWriter_);
210
211        this->memoryBuffer_ = new MemoryLogWriter();
212        // Write everything, e.g. use hardDebugLevel
213        this->memoryBuffer_->softDebugLevel_ = hardDebugLevel;
214        this->registerOutputListener(this->memoryBuffer_);
215    }
216
217    //! Destroys the LogFileWriter and the MemoryLogWriter
218    OutputHandler::~OutputHandler()
219    {
220        delete this->logFile_;
221        delete this->consoleWriter_;
222        delete this->memoryBuffer_; // Might already be NULL
223    }
224
225    OutputHandler& OutputHandler::getInstance()
226    {
227        static OutputHandler orxout;
228        return orxout;
229    }
230
231    void OutputHandler::registerOutputListener(OutputListener* listener)
232    {
233        for (std::vector<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
234        {
235            if ((*it)->name_ == listener->name_)
236            {
237                COUT(2) << "OutputHandler, Warning: Trying to register two listeners with the same name!" << std::endl;
238                return;
239            }
240        }
241        this->listeners_.push_back(listener);
242        this->updateGlobalDebugLevel();
243    }
244
245    void OutputHandler::unregisterOutputListener(OutputListener* listener)
246    {
247        for (std::vector<OutputListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
248        {
249            if ((*it)->name_ == listener->name_)
250            {
251                this->listeners_.erase(it);
252                break;
253            }
254        }
255        this->updateGlobalDebugLevel();
256    }
257
258    void OutputHandler::setLogPath(const std::string& path)
259    {
260        this->logFile_->setLogPath(path);
261    }
262
263    void OutputHandler::disableCout()
264    {
265        this->unregisterOutputListener(this->consoleWriter_);
266    }
267
268    void OutputHandler::enableCout()
269    {
270        this->registerOutputListener(this->consoleWriter_);
271    }
272
273    void OutputHandler::disableMemoryLog()
274    {
275        this->unregisterOutputListener(this->memoryBuffer_);
276        // Only clear the buffer so we can still reference the vector
277        this->memoryBuffer_->output_.clear();
278    }
279
280    const OutputHandler::OutputVector& OutputHandler::getOutput() const
281    {
282        return this->memoryBuffer_->output_;
283    }
284
285    int OutputHandler::getSoftDebugLevel(const std::string& name) const
286    {
287        for (std::vector<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        for (std::vector<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
298        {
299            if ((*it)->name_ == name)
300                (*it)->softDebugLevel_ = level;
301        }
302        this->updateGlobalDebugLevel();
303    }
304
305    void OutputHandler::updateGlobalDebugLevel()
306    {
307        int globalSoftDebugLevel = -1;
308        std::vector<OutputListener*>::const_iterator it = this->listeners_.begin();
309        for (; it != this->listeners_.end(); ++it)
310            globalSoftDebugLevel = std::max(globalSoftDebugLevel, (*it)->softDebugLevel_);
311
312        OutputHandler::softDebugLevel_s = globalSoftDebugLevel;
313    }
314}
Note: See TracBrowser for help on using the repository browser.