Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Nov 20, 2009, 4:55:40 PM (14 years ago)
Author:
rgrieder
Message:

Merged console branch back to trunk.

Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/libraries/util/OutputHandler.cc

    r5738 r6105  
    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 <sstream>
     42
     43#include "Debug.h"
    3844
    3945namespace orxonox
    4046{
     47    //! How the log file shall be named on the filesystem
     48    const std::string logFileBaseName_g = "orxonox.log";
     49
     50    /////////////////////////
     51    ///// LogFileWriter /////
     52    /////////////////////////
    4153    /**
    42         @brief Constructor: Opens the logfile and writes the first line.
    43         @param logfilename The name of the logfile
     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.
    4461    */
     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()
     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        }
     95
     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    ///// ConsoleWriter /////
     125    /////////////////////////
     126    /**
     127    @brief
     128        Writes the output to std::cout.
     129    @note
     130        This listener will usually be disable once an actual shell with console is instantiated.
     131    */
     132    class ConsoleWriter : public OutputListener
     133    {
     134    public:
     135        //! Only assigns the output stream with std::cout
     136        ConsoleWriter()
     137            : OutputListener("consoleLog")
     138        {
     139            this->outputStream_ = &std::cout;
     140        }
     141    };
     142
     143
     144    ///////////////////////////
     145    ///// MemoryLogWriter /////
     146    ///////////////////////////
     147    /**
     148    @brief
     149        OutputListener that writes all the output piece by piece to an array
     150        associated with the corresponding output level.
     151    @note
     152        Only output below or equal to the current soft debug level is written
     153        to minimise huge arrays for the normal run.
     154    */
     155    class MemoryLogWriter : public OutputListener
     156    {
     157    public:
     158        friend class OutputHandler;
     159
     160        /**
     161        @brief
     162            Sets the right soft debug level and registers itself
     163        @param outputHandler
     164            This is only required to avoid another call to getInstance (this c'tor was
     165            called from getInstance!)
     166        */
     167        MemoryLogWriter()
     168            : OutputListener("memoryLog")
     169        {
     170            this->outputStream_ = &this->buffer_;
     171        }
     172
     173        //! Pushed the just written output to the internal array
     174        void outputChanged(int level)
     175        {
     176            // Read ostringstream and store it
     177            this->output_.push_back(std::make_pair(level, this->buffer_.str()));
     178            // Clear content and flags
     179            this->buffer_.str(std::string());
     180            this->buffer_.clear();
     181        }
     182
     183    private:
     184        std::ostringstream                        buffer_; //! Stream object used to process the output
     185        std::vector<std::pair<int, std::string> > output_; //! Vector containing ALL output
     186    };
     187
     188
     189    /////////////////////////
     190    ///// OutputHandler /////
     191    /////////////////////////
     192    const std::string OutputHandler::logFileOutputListenerName_s = "logFile";
     193          int         OutputHandler::softDebugLevel_s = hardDebugLevel;
     194
     195    //! Creates the LogFileWriter and the MemoryLogWriter
    45196    OutputHandler::OutputHandler()
    46     {
    47 #ifdef ORXONOX_PLATFORM_WINDOWS
    48         char* pTempDir = getenv("TEMP");
    49         this->logfilename_ = std::string(pTempDir) + "/orxonox.log";
     197        : outputLevel_(OutputLevel::Verbose)
     198    {
     199#ifdef ORXONOX_RELEASE
     200        const OutputLevel::Value defaultLevelConsole = OutputLevel::Error;
     201        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Info;
    50202#else
    51         this->logfilename_ = "/tmp/orxonox.log";
     203        const OutputLevel::Value defaultLevelConsole = OutputLevel::Info;
     204        const OutputLevel::Value defaultLevelLogFile = OutputLevel::Debug;
    52205#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     */
     206
     207        this->logFile_ = new LogFileWriter();
     208        // Use default level until we get the configValue from the Core
     209        this->logFile_->softDebugLevel_ = defaultLevelLogFile;
     210        this->registerOutputListener(this->logFile_);
     211
     212        this->consoleWriter_ = new ConsoleWriter();
     213        this->consoleWriter_->softDebugLevel_ = defaultLevelConsole;
     214        this->registerOutputListener(this->consoleWriter_);
     215
     216        this->output_  = new MemoryLogWriter();
     217        // We capture as much input as the listener with the highest level
     218        this->output_->softDebugLevel_ = getSoftDebugLevel();
     219        this->registerOutputListener(this->output_);
     220    }
     221
     222    //! Destroys the LogFileWriter and the MemoryLogWriter
    76223    OutputHandler::~OutputHandler()
    77224    {
    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()
     225        delete this->logFile_;
     226        delete this->output_;
     227    }
     228
     229    OutputHandler& OutputHandler::getInstance()
    87230    {
    88231        static OutputHandler orxout;
     
    90233    }
    91234
    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     */
     235    void OutputHandler::registerOutputListener(OutputListener* listener)
     236    {
     237        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
     238        {
     239            if ((*it)->name_ == listener->name_)
     240            {
     241                COUT(2) << "OutputHandler, Warning: Trying to register two listeners with the same name!" << std::endl;
     242                return;
     243            }
     244        }
     245        this->listeners_.push_back(listener);
     246        // Update global soft debug level
     247        this->setSoftDebugLevel(listener->getOutputListenerName(), listener->getSoftDebugLevel());
     248    }
     249
     250    void OutputHandler::unregisterOutputListener(OutputListener* listener)
     251    {
     252        this->listeners_.remove(listener);
     253    }
     254
    131255    void OutputHandler::setLogPath(const std::string& path)
    132256    {
    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;
     257        this->logFile_->setLogPath(path);
     258    }
     259
     260    void OutputHandler::disableCout()
     261    {
     262        this->unregisterOutputListener(this->consoleWriter_);
     263    }
     264
     265    void OutputHandler::enableCout()
     266    {
     267        this->registerOutputListener(this->consoleWriter_);
     268    }
     269
     270    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorBegin() const
     271    {
     272        return this->output_->output_.begin();
     273    }
     274
     275    OutputHandler::OutputVectorIterator OutputHandler::getOutputVectorEnd() const
     276    {
     277        return this->output_->output_.end();
     278    }
     279
     280    int OutputHandler::getSoftDebugLevel(const std::string& name) const
     281    {
     282        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
     283        {
     284            if ((*it)->name_ == name)
     285                return (*it)->softDebugLevel_;
     286        }
     287        return -1;
     288    }
     289
     290    void OutputHandler::setSoftDebugLevel(const std::string& name, int level)
     291    {
     292        int globalSoftDebugLevel = -1;
     293        for (std::list<OutputListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
     294        {
     295            if ((*it)->name_ == name)
     296                (*it)->softDebugLevel_ = level;
     297            if ((*it)->softDebugLevel_ > globalSoftDebugLevel)
     298                globalSoftDebugLevel = (*it)->softDebugLevel_;
     299        }
     300        // Update global soft debug level
     301        OutputHandler::softDebugLevel_s = globalSoftDebugLevel;
    230302    }
    231303}
Note: See TracChangeset for help on using the changeset viewer.