Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

De-singletonised Shell so that both consoles have their own Shell instance. However they share the history.
Also modified IOConsole to hopefully work with status lines.

  • Property svn:eol-style set to native
File size: 8.4 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 <sstream>
42
43#include "Debug.h"
44
45namespace orxonox
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    /////////////////////////
53    /**
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.
61    */
62    class LogFileWriter : public OutputListener
63    {
64    public:
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        */
72        LogFileWriter(OutputHandler& outputHandler)
73            : OutputListener(OutputHandler::logFileOutputListenerName_s)
74        {
75            // Get path for a temporary file
76#ifdef ORXONOX_PLATFORM_WINDOWS
77            char* pTempDir = getenv("TEMP");
78            this->logFilename_ = std::string(pTempDir) + "/" + logFileBaseName_g;
79#else
80            this->logFilename_ = std::string("/tmp/") + logFileBaseName_g;
81#endif
82
83            // Get current time
84            time_t rawtime;
85            struct tm* timeinfo;
86            time(&rawtime);
87            timeinfo = localtime(&rawtime);
88
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();
92
93            this->outputStream_ = &this->logFile_;
94            // Use default level until we get the configValue from the Core
95            this->setSoftDebugLevel(OutputLevel::Debug);
96            outputHandler.registerOutputListener(this);
97        }
98
99        //! Closes the log file
100        ~LogFileWriter()
101        {
102            this->logFile_ << "Closed log" << std::endl;
103            this->logFile_.close();
104        }
105
106        //! Changes the log path
107        void setLogPath(const std::string& path)
108        {
109            this->logFile_.close();
110            // Read old file into a buffer
111            std::ifstream old(this->logFilename_.c_str());
112            this->logFilename_ = path + logFileBaseName_g;
113            // Open the new file and feed it the content of the old one
114            this->logFile_.open(this->logFilename_.c_str(), std::fstream::out);
115            this->logFile_ << old.rdbuf();
116            this->logFile_.flush();
117            old.close();
118        }
119
120    private:
121        std::ofstream logFile_;     //! File handle for the log file
122        std::string   logFilename_; //! Filename of the log file
123    };
124
125
126    ///////////////////////////
127    ///// MemoryLogWriter /////
128    ///////////////////////////
129    /**
130    @brief
131        OutputListener that writes all the output piece by piece to an array
132        associated with the corresponding output level.
133    @note
134        Only output below or equal to the current soft debug level is written
135        to minimise huge arrays for the normal run.
136    */
137    class MemoryLogWriter : public OutputListener
138    {
139    public:
140        friend class OutputHandler;
141
142        /**
143        @brief
144            Sets the right soft debug level and registers itself
145        @param outputHandler
146            This is only required to avoid another call to getInstance (this c'tor was
147            called from getInstance!)
148        */
149        MemoryLogWriter(OutputHandler& outputHandler)
150            : OutputListener("memoryLog")
151        {
152            this->outputStream_ = &this->buffer_;
153            // We capture as much input as the listener with the highest level
154            this->setSoftDebugLevel(OutputHandler::getSoftDebugLevel());
155            outputHandler.registerOutputListener(this);
156        }
157
158        //! Pushed the just written output to the internal array
159        void outputChanged(int level)
160        {
161            // Read ostringstream and store it
162            this->output_.push_back(std::make_pair(level, this->buffer_.str()));
163            // Clear content and flags
164            this->buffer_.str(std::string());
165            this->buffer_.clear();
166        }
167
168    private:
169        std::ostringstream                        buffer_; //! Stream object used to process the output
170        std::vector<std::pair<int, std::string> > output_; //! Vector containing ALL output
171    };
172
173
174    /////////////////////////
175    ///// OutputHandler /////
176    /////////////////////////
177    const std::string OutputHandler::logFileOutputListenerName_s = "logFile";
178          int         OutputHandler::softDebugLevel_s = hardDebugLevel;
179
180    //! Creates the LogFileWriter and the MemoryLogWriter
181    OutputHandler::OutputHandler()
182        : outputLevel_(OutputLevel::Verbose)
183    {
184        this->logFile_ = new LogFileWriter(*this);
185        this->output_  = new MemoryLogWriter(*this);
186    }
187
188    //! Destroys the LogFileWriter and the MemoryLogWriter
189    OutputHandler::~OutputHandler()
190    {
191        delete this->logFile_;
192        delete this->output_;
193    }
194
195    OutputHandler& OutputHandler::getInstance()
196    {
197        static OutputHandler orxout;
198        return orxout;
199    }
200
201    void OutputHandler::registerOutputListener(OutputListener* listener)
202    {
203        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
204        {
205            if ((*it)->name_ == listener->name_)
206            {
207                COUT(2) << "OutputHandler, Warning: Trying to register two listeners with the same name!" << std::endl;
208                return;
209            }
210        }
211        this->listeners_.push_back(listener);
212        // Update global soft debug level
213        this->setSoftDebugLevel(listener->getOutputListenerName(), listener->getSoftDebugLevel());
214    }
215
216    void OutputHandler::unregisterOutputListener(OutputListener* listener)
217    {
218        this->listeners_.remove(listener);
219    }
220
221    void OutputHandler::setLogPath(const std::string& path)
222    {
223        this->logFile_->setLogPath(path);
224    }
225
226    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const
227    {
228        return this->output_->output_.begin();
229    }
230
231    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const
232    {
233        return this->output_->output_.end();
234    }
235
236    int OutputHandler::getSoftDebugLevel(const std::string& name) const
237    {
238        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
239        {
240            if ((*it)->name_ == name)
241                return (*it)->softDebugLevel_;
242        }
243        return -1;
244    }
245
246    void OutputHandler::setSoftDebugLevel(const std::string& name, int level)
247    {
248        int globalSoftDebugLevel = -1;
249        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
250        {
251            if ((*it)->name_ == name)
252                (*it)->softDebugLevel_ = level;
253            if ((*it)->softDebugLevel_ > globalSoftDebugLevel)
254                globalSoftDebugLevel = (*it)->softDebugLevel_;
255        }
256        // Update global soft debug level
257        OutputHandler::softDebugLevel_s = globalSoftDebugLevel;
258    }
259}
Note: See TracBrowser for help on using the repository browser.