diff --git a/eo/src/utils/eoLogger.cpp b/eo/src/utils/eoLogger.cpp index 79813137c..10371b0a0 100644 --- a/eo/src/utils/eoLogger.cpp +++ b/eo/src/utils/eoLogger.cpp @@ -37,13 +37,17 @@ Caner Candan #include // used to define EOF #include +#include // std::find #include "eoLogger.h" -/* TODO? -- changer oprateurs -- virer la structure "file" -*/ + +#ifdef USE_SET +typedef std::set::iterator StreamIter; +#else +typedef std::vector::iterator StreamIter; +#endif + void eoLogger::_init() { @@ -61,7 +65,7 @@ void eoLogger::_init() } eoLogger::eoLogger() : - std::ostream(NULL), + std::ostream(NULL), _verbose("quiet", "verbose", "Set the verbose level", 'v'), _printVerboseLevels(false, "print-verbose-levels", "Print verbose levels", 'l'), @@ -71,16 +75,15 @@ eoLogger::eoLogger() : _contextLevel(eo::quiet), _obuf(_contextLevel, _selectedLevel) { - std::ostream::init(&_obuf); + std::ostream::init(&_obuf); _init(); } eoLogger::~eoLogger() { - //redirect(NULL); - if (_obuf._ownedFileStream != NULL) { - delete _obuf._ownedFileStream; - } + if (_obuf._ownedFileStream != NULL) { + delete _obuf._ownedFileStream; + } } void eoLogger::_createParameters( eoParser& parser ) @@ -161,29 +164,68 @@ eoLogger& operator<<(eoLogger& l, eo::setlevel v) eoLogger& operator<<(eoLogger& l, std::ostream& os) { - l._obuf._outStream = &os; +#warning deprecated + l.addRedirect(os); return l; } void eoLogger::redirect(std::ostream& os) { - if (_obuf._ownedFileStream != NULL) { - delete _obuf._ownedFileStream; - _obuf._ownedFileStream = NULL; - } - _obuf._outStream = &os; + doRedirect(&os); +} + +void eoLogger::doRedirect(std::ostream* os) +{ + if (_obuf._ownedFileStream != NULL) { + delete _obuf._ownedFileStream; + _obuf._ownedFileStream = NULL; + } + _obuf._outStreams.clear(); + if (os != NULL) + #ifdef USE_SET + _obuf._outStreams.insert(os); + #else + _obuf._outStreams.push_back(os); + #endif +} + +void eoLogger::addRedirect(std::ostream& os) +{ + bool already_there = tryRemoveRedirect(&os); +#ifdef USE_SET + _obuf._outStreams.insert(&os); +#else + _obuf._outStreams.push_back(&os); +#endif + if (already_there) + eo::log << eo::warnings << "Cannot redirect the logger to a stream it is already redirected to." << std::endl; +} + +void eoLogger::removeRedirect(std::ostream& os) +{ + if (!tryRemoveRedirect(&os)) + eo::log << eo::warnings << "Cannot remove from the logger a stream it was not redirected to."; +} + +bool eoLogger::tryRemoveRedirect(std::ostream* os) +{ + StreamIter it = find(_obuf._outStreams.begin(), _obuf._outStreams.end(), os); + if (it == _obuf._outStreams.end()) + return false; + _obuf._outStreams.erase(it); + return true; } void eoLogger::redirect(const char * filename) { - std::ofstream * os; - if (filename == NULL) { - os = NULL; - } else { - os = new std::ofstream(filename); - } - redirect(*os); - _obuf._ownedFileStream = os; + std::ofstream * os; + if (filename == NULL) { + os = NULL; + } else { + os = new std::ofstream(filename); + } + doRedirect(os); + _obuf._ownedFileStream = os; } void eoLogger::redirect(const std::string& filename) @@ -194,18 +236,29 @@ void eoLogger::redirect(const std::string& filename) eoLogger::outbuf::outbuf(const eo::Levels& contexlvl, const eo::Levels& selectedlvl) - : _outStream(&std::cout), _ownedFileStream(NULL), _contextLevel(contexlvl), _selectedLevel(selectedlvl) -{} + : +#ifndef USE_SET + _outStreams(1, &std::cout), +#endif + _ownedFileStream(NULL), _contextLevel(contexlvl), _selectedLevel(selectedlvl) +{ +#ifdef USE_SET + _outStreams.insert(&std::cout); +#endif +} int eoLogger::outbuf::overflow(int_type c) { if (_selectedLevel >= _contextLevel) - { - if (_outStream && c != EOF) - { - (*_outStream) << (char) c; - } - } + { + for (StreamIter it = _outStreams.begin(); it != _outStreams.end(); it++) + { + if (c != EOF) + { + (**it) << (char) c; + } + } + } return c; } diff --git a/eo/src/utils/eoLogger.h b/eo/src/utils/eoLogger.h index e655848c7..98ba09660 100644 --- a/eo/src/utils/eoLogger.h +++ b/eo/src/utils/eoLogger.h @@ -1,6 +1,7 @@ // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- /* + (c) Thales group, 2010 This library is free software; you can redistribute it and/or @@ -30,56 +31,7 @@ Caner Candan Global logger for EO. - Here's an example explaning how to use eoLogger: -\code - #include - - int main(int ac, char** av) - { - // We are declaring the usual eoParser class - eoParser parser(ac, av); - - // This call is important to allow -v parameter to change user level. - make_verbose(parser); - - // At this time we are switching to warning message and messages - // which are going to follow it are going to be warnings message too. - // These messages can be displayed only if the user level (sets with - // eo::setlevel function) is set to eo::warnings. - eo::log << eo::warnings; - - // With the following eo::file function we are defining that - // all future logs are going to this new file resource which is - // test.txt - eo::log << eo::file("test.txt") << "In FILE" << std::endl; - - // Now we are changing again the resources destination to cout which - // is the standard output. - eo::log << std::cout << "In COUT" << std::endl; - - // Here are 2 differents examples of how to set the errors user level - // in using either a string or an identifier. - eo::log << eo::setlevel("errors"); - eo::log << eo::setlevel(eo::errors); - - // Now we are writting a message, that will be displayed only if we are above the "quiet" level - eo::log << eo::quiet << "1) Must be in quiet mode to see that" << std::endl; - - // And so on... - eo::log << eo::setlevel(eo::warnings) << eo::warnings << "2) Must be in warnings mode to see that" << std::endl; - - eo::log << eo::setlevel(eo::logging); - - eo::log << eo::errors; - eo::log << "3) Must be in errors mode to see that"; - eo::log << std::endl; - - eo::log << eo::debug << 4 << ')' - << " Must be in debug mode to see that\n"; - - return 0; - } -\endcode + For an example explaning how to use eoLogger, please refer to paradiseo/eo/test/t-eoLogger.cpp @{ */ @@ -96,6 +48,18 @@ Caner Candan #include "eoObject.h" #include "eoParser.h" +#define USE_SET // defines if a set is to be used instead of a vector for storing streams the logger is redirected to +#undef USE_SET +/* expriments have shown that here a vector is by far faster than a set even if O(n), + * because it needs less dynamic allocations, uses less memory and less instructions + */ + + +#ifdef USE_SET +#include +#endif + + namespace eo { /** @@ -111,16 +75,6 @@ namespace eo debug, xdebug}; - /** - * file - * this structure combined with the friend operator<< below is an easy way to select a file as output. - * - struct file - { - explicit file(const std::string f); - const std::string _f; - };*/ - /** * setlevel * this structure combined with the friend operator<< below is an easy way to set a verbose level. @@ -182,6 +136,12 @@ private: //! used by the set of ctors to initiate some useful variables void _init(); + //! helper function regrouping redirection operations; takes a pointer because can be given NULL + void doRedirect(std::ostream*); + + //! helper function searching for a stream and removing it, returning true if successful, false otherwise + bool tryRemoveRedirect(std::ostream*); + private: /** * outbuf @@ -191,7 +151,14 @@ private: { public: outbuf(const eo::Levels& contexlvl, const eo::Levels& selectedlvl); - std::ostream * _outStream; + //std::ostream * _outStream; + + #ifdef USE_SET + std::set _outStreams; + #else + std::vector _outStreams; + #endif + std::ofstream * _ownedFileStream; protected: virtual int overflow(int_type c); @@ -220,20 +187,32 @@ public: friend eoLogger& operator<<(eoLogger&, eo::setlevel); /** - * DEPRECATED: Use instead the redirectTo method - * operator<< used there to be able to use std::cout to say that we wish to redirect back the buffer to a standard output. + * DEPRECATED: Use instead the redirect or addRedirect method; has the same effect as addRedirect */ - //! in order to use stream style to go back to a standart output defined by STL - //! and to get retro-compatibility -#warning deprecated friend eoLogger& operator<<(eoLogger&, std::ostream&); /** - * Redirects the logger to a given output stream. Closing the stream and returning its memory is at the charge of the caller, + * Redirects the logger to a given output stream. + * Closing the stream and returning its memory is at the charge of the caller, * but should not be done while the log is still redirected to it. + * This resets all previous redirections set up with redirect and add_redirect. */ void redirect(std::ostream&); + /** + * Adds a redirection from the logger to a given output stream. + * Closing the stream and returning its memory is at the charge of the caller, + * but should not be done while the log is still redirected to it. + * This does not reset previous redirections, which remain active. + */ + void addRedirect(std::ostream&); + + /** + * Removes a redirection from the logger to the given output stream. + * This only resets the redirection to the stream passed in argument. + */ + void removeRedirect(std::ostream&); + /** * Redirects the logger to a file using a filename. * Closing the file will be done automatically when the logger is redirected again or destroyed. diff --git a/eo/test/t-eoLogger.cpp b/eo/test/t-eoLogger.cpp index a1ea4b60c..0406cb6b1 100644 --- a/eo/test/t-eoLogger.cpp +++ b/eo/test/t-eoLogger.cpp @@ -7,50 +7,75 @@ #include #include #include +#include //----------------------------------------------------------------------------- +static void test(); + int main(int ac, char** av) { eoParser parser(ac, av); if (parser.userNeedsHelp()) - { - parser.printHelp(std::cout); - exit(1); - } + { + parser.printHelp(std::cout); + exit(1); + } make_help(parser); make_verbose(parser); + test(); + + return 0; +} + +static void test() +{ eo::log << eo::setlevel(eo::debug); eo::log << eo::warnings; eo::log << "We are writing on the default output stream" << std::endl; - //eo::log << eo::file("test.txt") << "In FILE" << std::endl; + { + eo::log.redirect("logtest.txt"); + eo::log << "In FILE" << std::endl; + std::ofstream ofs("logtest2.txt"); // closed and destroyed at the en of the scope + eo::log.addRedirect(ofs); + eo::log << "In FILE 2" << std::endl; + eo::log.removeRedirect(ofs); // must be removed because the associated stream is closed + } - std::ofstream ofs("logtest.txt"); - //eo::log << ofs << "In FILE" << std::endl; - eo::log.redirect(ofs); - eo::log << "In FILE" << std::endl; - - eo::log.redirect("logtest2.txt"); - eo::log << "In FILE 2" << std::endl; + std::ifstream ifs("logtest2.txt"); // stream to logtest2.txt is closed, we can start reading + std::string line; + assert(std::getline(ifs, line)); + assert(line == "In FILE 2"); + assert(!std::getline(ifs, line)); std::ostringstream oss; - //eo::log << oss << "In STRINGSTREAM"; - eo::log.redirect(oss); - eo::log << oss << "In STRINGSTREAM"; + eo::log.addRedirect(oss); + eo::log << "In STRINGSTREAM"; - //ofs << oss; std::cout << "Content of ostringstream: " << oss.str() << std::endl; + assert(oss.str() == "In STRINGSTREAM"); - //eo::log << std::cout << "on COUT" << std::endl; - eo::log.redirect(std::cout); + eo::log.redirect(std::cout); // removes all previously redirected streams; closes the file logtest.txt eo::log << "on COUT" << std::endl; + + ifs.close(); + ifs.open("logtest.txt"); + assert(std::getline(ifs, line)); + assert(line == "In FILE"); + assert(std::getline(ifs, line)); + assert(line == "In FILE 2"); + assert(std::getline(ifs, line)); + assert(line == "In STRINGSTREAM"); + assert(!std::getline(ifs, line)); + + eo::log << eo::setlevel("errors"); eo::log << eo::setlevel(eo::errors); @@ -65,9 +90,8 @@ int main(int ac, char** av) eo::log << std::endl; eo::log << eo::debug << 4 << ')' - << "4) in debug mode\n"; - - return 0; + << "4) in debug mode\n"; + } //-----------------------------------------------------------------------------