Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Dec 25, 2009, 1:18:03 PM (15 years ago)
Author:
dafrick
Message:

Merged presentation2 branch into pickup2 branch.

Location:
code/branches/pickup2
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/branches/pickup2

  • code/branches/pickup2/src/libraries/util/OutputHandler.cc

    r5738 r6412  
    2323 *      Fabian 'x3n' Landau
    2424 *   Co-authors:
    25  *      ...
     25 *      Reto Grieder
    2626 *
    2727 */
    2828
    2929/**
    30     @file
    31     @brief Implementation of the OutputHandler class.
     30@file
     31@brief
     32    Definition of classes related to output (logging).
    3233*/
    3334
    3435#include "OutputHandler.h"
    3536
     37#include <algorithm>
    3638#include <ctime>
    3739#include <cstdlib>
     40#include <fstream>
     41#include <iostream>
     42#include <sstream>
     43
     44#include "Debug.h"
    3845
    3946namespace orxonox
    4047{
     48    //! How the log file shall be named on the filesystem
     49    const std::string logFileBaseName_g = "orxonox.log";
     50
     51    /////////////////////////
     52    ///// LogFileWriter /////
     53    /////////////////////////
    4154    /**
    42         @brief Constructor: Opens the logfile and writes the first line.
    43         @param logfilename The name of the logfile
     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.
    4462    */
     63    class LogFileWriter : public OutputListener
     64    {
     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
     77#ifdef ORXONOX_PLATFORM_WINDOWS
     78            char* pTempDir = getenv("TEMP");
     79            this->logFilename_ = std::string(pTempDir) + '/' + logFileBaseName_g;
     80#else
     81            this->logFilename_ = std::string("/tmp/") + logFileBaseName_g;
     82#endif
     83
     84            // Get current time
     85            time_t rawtime;
     86            struct tm* timeinfo;
     87            time(&rawtime);
     88            timeinfo = localtime(&rawtime);
     89
     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();
     93
     94            this->outputStream_ = &this->logFile_;
     95        }
     96
     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    /////////////////////////
     127    /**
     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.
     132    */
     133    class ConsoleWriter : public OutputListener
     134    {
     135    public:
     136        //! Only assigns the output stream with std::cout
     137        ConsoleWriter()
     138            : OutputListener("consoleLog")
     139        {
     140            this->outputStream_ = &std::cout;
     141        }
     142    };
     143
     144
     145    ///////////////////////////
     146    ///// MemoryLogWriter /////
     147    ///////////////////////////
     148    /**
     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.
     155    */
     156    class MemoryLogWriter : public OutputListener
     157    {
     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        {
     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            }
     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
    45200    OutputHandler::OutputHandler()
    46     {
    47 #ifdef ORXONOX_PLATFORM_WINDOWS
    48         char* pTempDir = getenv("TEMP");
    49         this->logfilename_ = std::string(pTempDir) + "/orxonox.log";
     201        : outputLevel_(OutputLevel::Verbose)
     202    {
     203#ifdef ORXONOX_RELEASE
     204        const OutputLevel::Value defaultLevelConsole = OutputLevel::Error;
     205        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Info;
    50206#else
    51         this->logfilename_ = "/tmp/orxonox.log";
     207        const OutputLevel::Value defaultLevelConsole = OutputLevel::Info;
     208        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Debug;
    52209#endif
    53 #ifdef NDEBUG
    54         this->softDebugLevel_[LD_All] = this->softDebugLevel_[LD_Logfile] = 2;
    55         this->softDebugLevel_[LD_Console] = this->softDebugLevel_[LD_Shell] = 1;
    56 #else
    57         this->softDebugLevel_[LD_All] = this->softDebugLevel_[LD_Logfile] = 3;
    58         this->softDebugLevel_[LD_Console] = this->softDebugLevel_[LD_Shell] = 2;
    59 #endif
    60 
    61         this->outputBuffer_ = &this->fallbackBuffer_;
    62         this->logfile_.open(this->logfilename_.c_str(), std::fstream::out);
    63 
    64         time_t rawtime;
    65         struct tm* timeinfo;
    66         time(&rawtime);
    67         timeinfo = localtime(&rawtime);
    68 
    69         this->logfile_ << "Started log on " << asctime(timeinfo) << std::endl;
    70         this->logfile_.flush();
    71     }
    72 
    73     /**
    74         @brief Destructor: Writes the last line to the logfile and closes it.
    75     */
     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
     220        this->output_ = new MemoryLogWriter();
     221        // We capture as much input as the listener with the highest level
     222        this->output_->softDebugLevel_ = getSoftDebugLevel();
     223        this->registerOutputListener(this->output_);
     224    }
     225
     226    //! Destroys the LogFileWriter and the MemoryLogWriter
    76227    OutputHandler::~OutputHandler()
    77228    {
    78         this->logfile_ << "Closed log" << std::endl;
    79         this->logfile_.close();
    80     }
    81 
    82     /**
    83         @brief Returns a reference to the only existing instance of the OutputHandler class.
    84         @return The instance
    85     */
    86     OutputHandler& OutputHandler::getOutStream()
     229        delete this->logFile_;
     230        delete this->consoleWriter_;
     231        delete this->output_;
     232    }
     233
     234    OutputHandler& OutputHandler::getInstance()
    87235    {
    88236        static OutputHandler orxout;
     
    90238    }
    91239
    92     /**
    93         @brief Sets the soft debug level for a given output device.
    94         @param device The output device
    95         @param level The debug level
    96     */
    97     void OutputHandler::setSoftDebugLevel(OutputHandler::OutputDevice device, int level)
    98     {
    99         OutputHandler::getOutStream().softDebugLevel_[static_cast<unsigned int>(device)] = level;
    100     }
    101 
    102     /**
    103         @brief Returns the soft debug level for a given output device.
    104         @param device The output device
    105         @return The debug level
    106     */
    107     int OutputHandler::getSoftDebugLevel(OutputHandler::OutputDevice device)
    108     {
    109         return OutputHandler::getOutStream().softDebugLevel_[static_cast<unsigned int>(device)];
    110     }
    111 
    112     /**
    113         @brief Sets the OutputBuffer, representing the third output stream.
    114         @param buffer The OutputBuffer
    115     */
    116     void OutputHandler::setOutputBuffer(OutputBuffer* buffer)
    117     {
    118         if (buffer == NULL)
    119             this->outputBuffer_ = &this->fallbackBuffer_;
    120         else
    121         {
    122             buffer->getStream() >> this->outputBuffer_->getStream().rdbuf();
    123             this->outputBuffer_ = buffer;
    124         }
    125     }
    126 
    127     /**
    128         @brief Sets the path where to create orxonox.log
    129         @param Path string with trailing slash
    130     */
     240    void OutputHandler::registerOutputListener(OutputListener* listener)
     241    {
     242        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
     243        {
     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            }
     249        }
     250        this->listeners_.push_back(listener);
     251        // Update global soft debug level
     252        this->setSoftDebugLevel(listener->getOutputListenerName(), listener->getSoftDebugLevel());
     253    }
     254
     255    void OutputHandler::unregisterOutputListener(OutputListener* listener)
     256    {
     257        this->listeners_.remove(listener);
     258    }
     259
    131260    void OutputHandler::setLogPath(const std::string& path)
    132261    {
    133         OutputHandler::getOutStream().logfile_.close();
    134         // store old content
    135         std::ifstream old;
    136         old.open(OutputHandler::getOutStream().logfilename_.c_str());
    137         OutputHandler::getOutStream().logfilename_ = path + "orxonox.log";
    138         OutputHandler::getOutStream().logfile_.open(OutputHandler::getOutStream().logfilename_.c_str(), std::fstream::out);
    139         OutputHandler::getOutStream().logfile_ << old.rdbuf();
    140         old.close();
    141         OutputHandler::getOutStream().logfile_.flush();
    142     }
    143 
    144     /**
    145         @brief Overloaded << operator, redirects the output to the console and the logfile.
    146         @param sb The streambuffer that should be shown in the console
    147         @return A reference to the OutputHandler itself
    148     */
    149     OutputHandler& OutputHandler::operator<<(std::streambuf* sb)
    150     {
    151         if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_)
    152             std::cout << sb;
    153 
    154         if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_)
    155         {
    156             this->logfile_ << sb;
    157             this->logfile_.flush();
    158         }
    159 
    160         if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_)
    161             (*this->outputBuffer_) << sb;
    162 
    163         return *this;
    164     }
    165 
    166     /**
    167         @brief Overloaded << operator, redirects the output to the console, the logfile and the ingame shell.
    168         @param manipulator A function, manipulating the outstream.
    169         @return A reference to the OutputHandler itself
    170     */
    171     OutputHandler& OutputHandler::operator<<(std::ostream& (*manipulator)(std::ostream&))
    172     {
    173         if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_)
    174             manipulator(std::cout);
    175 
    176         if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_)
    177         {
    178             manipulator(this->logfile_);
    179             this->logfile_.flush();
    180         }
    181 
    182         if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_)
    183             (*this->outputBuffer_) << manipulator;
    184 
    185         return *this;
    186     }
    187 
    188     /**
    189         @brief Overloaded << operator, redirects the output to the console, the logfile and the ingame shell.
    190         @param manipulator A function, manipulating the outstream.
    191         @return A reference to the OutputHandler itself
    192     */
    193     OutputHandler& OutputHandler::operator<<(std::ios& (*manipulator)(std::ios&))
    194     {
    195         if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_)
    196             manipulator(std::cout);
    197 
    198         if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_)
    199         {
    200             manipulator(this->logfile_);
    201             this->logfile_.flush();
    202         }
    203 
    204         if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_)
    205             (*this->outputBuffer_) << manipulator;
    206 
    207         return *this;
    208     }
    209 
    210     /**
    211         @brief Overloaded << operator, redirects the output to the console, the logfile and the ingame shell.
    212         @param manipulator A function, manipulating the outstream.
    213         @return A reference to the OutputHandler itself
    214     */
    215     OutputHandler& OutputHandler::operator<<(std::ios_base& (*manipulator)(std::ios_base&))
    216     {
    217         if (getSoftDebugLevel(OutputHandler::LD_Console) >= this->outputLevel_)
    218             manipulator(std::cout);
    219 
    220         if (getSoftDebugLevel(OutputHandler::LD_Logfile) >= this->outputLevel_)
    221         {
    222             manipulator(this->logfile_);
    223             this->logfile_.flush();
    224         }
    225 
    226         if (OutputHandler::getSoftDebugLevel(OutputHandler::LD_Shell) >= this->outputLevel_)
    227             (*this->outputBuffer_) << manipulator;
    228 
    229         return *this;
     262        this->logFile_->setLogPath(path);
     263    }
     264
     265    void OutputHandler::disableCout()
     266    {
     267        this->unregisterOutputListener(this->consoleWriter_);
     268    }
     269
     270    void OutputHandler::enableCout()
     271    {
     272        this->registerOutputListener(this->consoleWriter_);
     273    }
     274
     275    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const
     276    {
     277        return this->output_->output_.begin();
     278    }
     279
     280    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const
     281    {
     282        return this->output_->output_.end();
     283    }
     284
     285    int OutputHandler::getSoftDebugLevel(const std::string& name) const
     286    {
     287        for (std::list<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        int globalSoftDebugLevel = -1;
     298        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
     299        {
     300            if ((*it)->name_ == name)
     301                (*it)->softDebugLevel_ = level;
     302            if ((*it)->softDebugLevel_ > globalSoftDebugLevel)
     303                globalSoftDebugLevel = (*it)->softDebugLevel_;
     304        }
     305        // Update global soft debug level
     306        OutputHandler::softDebugLevel_s = globalSoftDebugLevel;
    230307    }
    231308}
Note: See TracChangeset for help on using the changeset viewer.