Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Changed Output concept a little bit to allow for more general use.
Every output (log) target has to be implemented as OutputListener. There is already a LogFileWriter and a MemoryLogWriter (stores ALL the log in a vector and provides iterators).
The OutputListener has a unique and constant name, a stream pointer and a soft debug level (that can only be changed via OutputHandler::setSoftDebugLevel(name, level)).
This concept doesn't require the OutputBuffer anymore, so I deleted it.

The adjustments in the Shell are just preliminary for this commit.

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