This commit is contained in:
Lionel Parreaux 2025-05-02 17:01:34 +00:00 committed by GitHub
commit f540031fe2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 229 additions and 140 deletions

View file

@ -23,6 +23,7 @@ Contact: http://eodev.sourceforge.net
Authors: Authors:
Johann Dréo <johann.dreo@thalesgroup.com> Johann Dréo <johann.dreo@thalesgroup.com>
Caner Candan <caner.candan@thalesgroup.com> Caner Candan <caner.candan@thalesgroup.com>
Lionel Parreaux <lionel.parreaux@gmail.com>
*/ */
@ -37,14 +38,20 @@ Caner Candan <caner.candan@thalesgroup.com>
#include <cstdio> // used to define EOF #include <cstdio> // used to define EOF
#include <iostream> #include <iostream>
#include <algorithm> // std::find
#include "eoLogger.h" #include "eoLogger.h"
#ifdef USE_SET
typedef std::set<std::ostream*>::iterator StreamIter;
#else
typedef std::vector<std::ostream*>::iterator StreamIter;
#endif
void eoLogger::_init() void eoLogger::_init()
{ {
_standard_io_streams[&std::cout] = 1;
_standard_io_streams[&std::clog] = 2;
_standard_io_streams[&std::cerr] = 2;
// /!\ If you want to add a level dont forget to add it at the header file in the enumerator Levels // /!\ If you want to add a level dont forget to add it at the header file in the enumerator Levels
@ -55,10 +62,11 @@ void eoLogger::_init()
addLevel("logging", eo::logging); addLevel("logging", eo::logging);
addLevel("debug", eo::debug); addLevel("debug", eo::debug);
addLevel("xdebug", eo::xdebug); addLevel("xdebug", eo::xdebug);
} }
eoLogger::eoLogger() : eoLogger::eoLogger() :
std::ostream(NULL), std::ostream(NULL),
_verbose("quiet", "verbose", "Set the verbose level", 'v'), _verbose("quiet", "verbose", "Set the verbose level", 'v'),
_printVerboseLevels(false, "print-verbose-levels", "Print verbose levels", 'l'), _printVerboseLevels(false, "print-verbose-levels", "Print verbose levels", 'l'),
@ -66,33 +74,17 @@ eoLogger::eoLogger() :
_selectedLevel(eo::progress), _selectedLevel(eo::progress),
_contextLevel(eo::quiet), _contextLevel(eo::quiet),
_fd(2), _obuf(_contextLevel, _selectedLevel)
_obuf(_fd, _contextLevel, _selectedLevel)
{ {
std::ostream::init(&_obuf); std::ostream::init(&_obuf);
_init(); _init();
} }
eoLogger::eoLogger(eo::file file) :
std::ostream(NULL),
_verbose("quiet", "verbose", "Set the verbose level", 'v'),
_printVerboseLevels(false, "print-verbose-levels", "Print verbose levels", 'l'),
_output("", "output", "Redirect a standard output to a file", 'o'),
_selectedLevel(eo::progress),
_contextLevel(eo::quiet),
_fd(2),
_obuf(_fd, _contextLevel, _selectedLevel)
{
std::ostream::init(&_obuf);
_init();
*this << file;
}
eoLogger::~eoLogger() eoLogger::~eoLogger()
{ {
if (_fd > 2) { ::close(_fd); } if (_obuf._ownedFileStream != NULL) {
delete _obuf._ownedFileStream;
}
} }
void eoLogger::_createParameters( eoParser& parser ) void eoLogger::_createParameters( eoParser& parser )
@ -110,19 +102,21 @@ void eoLogger::_createParameters( eoParser& parser )
//------------------------------------------------------------------ //------------------------------------------------------------------
// we're gonna redirect the log to the given filename if -o is used. // we redirect the log to the given filename if -o is used.
//------------------------------------------------------------------ //------------------------------------------------------------------
if ( ! _output.value().empty() ) if ( ! _output.value().empty() )
{ {
eo::log << eo::file( _output.value() ); redirect(_output.value());
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
//------------------------------------------------------------------ //------------------------------------------------------------------
// we're gonna print the list of levels if -l parameter is used. // we print the list of levels if -l parameter is used.
//------------------------------------------------------------------ //------------------------------------------------------------------
if ( _printVerboseLevels.value() ) if ( _printVerboseLevels.value() )
@ -163,12 +157,6 @@ eoLogger& operator<<(eoLogger& l, const eo::Levels lvl)
return l; return l;
} }
eoLogger& operator<<(eoLogger& l, eo::file f)
{
l._fd = ::open(f._f.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
return l;
}
eoLogger& operator<<(eoLogger& l, eo::setlevel v) eoLogger& operator<<(eoLogger& l, eo::setlevel v)
{ {
l._selectedLevel = (v._lvl < 0 ? l._levels[v._v] : v._lvl); l._selectedLevel = (v._lvl < 0 ? l._levels[v._v] : v._lvl);
@ -177,37 +165,106 @@ eoLogger& operator<<(eoLogger& l, eo::setlevel v)
eoLogger& operator<<(eoLogger& l, std::ostream& os) eoLogger& operator<<(eoLogger& l, std::ostream& os)
{ {
if (l._standard_io_streams.find(&os) != l._standard_io_streams.end()) #warning deprecated
{ l.addRedirect(os);
l._fd = l._standard_io_streams[&os];
}
return l; return l;
} }
eoLogger::outbuf::outbuf(const int& fd, void eoLogger::redirect(std::ostream& os)
const eo::Levels& contexlvl, {
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);
}
doRedirect(os);
_obuf._ownedFileStream = os;
}
void eoLogger::redirect(const std::string& filename)
{
redirect(filename.c_str());
}
eoLogger::outbuf::outbuf(const eo::Levels& contexlvl,
const eo::Levels& selectedlvl) const eo::Levels& selectedlvl)
: _fd(fd), _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) int eoLogger::outbuf::overflow(int_type c)
{ {
if (_selectedLevel >= _contextLevel) if (_selectedLevel >= _contextLevel)
{ {
if (_fd >= 0 && c != EOF) for (StreamIter it = _outStreams.begin(); it != _outStreams.end(); it++)
{ {
::write(_fd, &c, 1); if (c != EOF)
} {
} (**it) << (char) c;
}
}
}
return c; return c;
} }
namespace eo namespace eo
{ {
file::file(const std::string f)
: _f(f)
{}
setlevel::setlevel(const std::string v) setlevel::setlevel(const std::string v)
: _v(v), _lvl((Levels)-1) : _v(v), _lvl((Levels)-1)
{} {}

View file

@ -1,6 +1,7 @@
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
/* /*
(c) Thales group, 2010 (c) Thales group, 2010
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
@ -22,6 +23,7 @@ Contact: http://eodev.sourceforge.net
Authors: Authors:
Johann Dréo <johann.dreo@thalesgroup.com> Johann Dréo <johann.dreo@thalesgroup.com>
Caner Candan <caner.candan@thalesgroup.com> Caner Candan <caner.candan@thalesgroup.com>
Lionel Parreaux <lionel.parreaux@gmail.com>
*/ */
@ -30,56 +32,7 @@ Caner Candan <caner.candan@thalesgroup.com>
Global logger for EO. Global logger for EO.
Here's an example explaning how to use eoLogger: For an example explaning how to use eoLogger, please refer to paradiseo/eo/test/t-eoLogger.cpp
\code
#include <eo>
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
@{ @{
*/ */
@ -91,10 +44,23 @@ Caner Candan <caner.candan@thalesgroup.com>
#include <vector> #include <vector>
#include <string> #include <string>
#include <iosfwd> #include <iosfwd>
#include <fstream>
#include "../eoObject.h" #include "../eoObject.h"
#include "eoParser.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 <set>
#endif
namespace eo namespace eo
{ {
/** /**
@ -110,16 +76,6 @@ namespace eo
debug, debug,
xdebug}; 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 * setlevel
* this structure combined with the friend operator<< below is an easy way to set a verbose level. * this structure combined with the friend operator<< below is an easy way to set a verbose level.
@ -145,7 +101,7 @@ public:
eoLogger(); eoLogger();
//! overidded ctor in order to instanciate a logger with a file define in parameter //! overidded ctor in order to instanciate a logger with a file define in parameter
eoLogger(eo::file file); //eoLogger(eo::file file);
//! dtor //! dtor
~eoLogger(); ~eoLogger();
@ -180,6 +136,12 @@ private:
//! used by the set of ctors to initiate some useful variables //! used by the set of ctors to initiate some useful variables
void _init(); 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: private:
/** /**
* outbuf * outbuf
@ -188,11 +150,19 @@ private:
class outbuf : public std::streambuf class outbuf : public std::streambuf
{ {
public: public:
outbuf(const int& fd, const eo::Levels& contexlvl, const eo::Levels& selectedlvl); outbuf(const eo::Levels& contexlvl, const eo::Levels& selectedlvl);
//std::ostream * _outStream;
#ifdef USE_SET
std::set<std::ostream*> _outStreams;
#else
std::vector<std::ostream*> _outStreams;
#endif
std::ofstream * _ownedFileStream;
protected: protected:
virtual int overflow(int_type c); virtual int overflow(int_type c);
private: private:
const int& _fd;
const eo::Levels& _contextLevel; const eo::Levels& _contextLevel;
const eo::Levels& _selectedLevel; const eo::Levels& _selectedLevel;
}; };
@ -210,12 +180,6 @@ public:
//! in order to use stream style to define the context verbose level where the following logs will be saved //! in order to use stream style to define the context verbose level where the following logs will be saved
friend eoLogger& operator<<(eoLogger&, const eo::Levels); friend eoLogger& operator<<(eoLogger&, const eo::Levels);
/**
* operator<< used there to set a filename through the class file.
*/
//! in order to use stream style to define a file to dump instead the standart output
friend eoLogger& operator<<(eoLogger&, eo::file);
/** /**
* operator<< used there to set a verbose level through the class setlevel. * operator<< used there to set a verbose level through the class setlevel.
*/ */
@ -223,12 +187,39 @@ public:
friend eoLogger& operator<<(eoLogger&, eo::setlevel); friend eoLogger& operator<<(eoLogger&, eo::setlevel);
/** /**
* 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
friend eoLogger& operator<<(eoLogger&, std::ostream&); 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,
* 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.
*/
void redirect(const char * filename);
void redirect(const std::string& filename);
private: private:
friend void make_verbose(eoParser&); friend void make_verbose(eoParser&);
@ -243,13 +234,7 @@ private:
eo::Levels _contextLevel; eo::Levels _contextLevel;
/** /**
* _fd in storing the file descriptor at this place we can disable easily the buffer in * _obuf std::ostream mandates to use a buffer. _obuf is a outbuf inheriting from std::streambuf.
* changing the value at -1. It is used by operator <<.
*/
int _fd;
/**
* _obuf std::ostream mandates to use a buffer. _obuf is a outbuf inheriting of std::streambuf.
*/ */
outbuf _obuf; outbuf _obuf;

View file

@ -3,30 +3,78 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include <eo> #include <eo>
//#include <paradiseo/eo.h>
#include <fstream>
#include <sstream>
#include <string>
#include <cassert>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static void test();
int main(int ac, char** av) int main(int ac, char** av)
{ {
eoParser parser(ac, av); eoParser parser(ac, av);
if (parser.userNeedsHelp()) if (parser.userNeedsHelp())
{ {
parser.printHelp(std::cout); parser.printHelp(std::cout);
exit(1); exit(1);
} }
make_help(parser); make_help(parser);
make_verbose(parser); make_verbose(parser);
test();
return 0;
}
static void test()
{
eo::log << eo::setlevel(eo::debug); eo::log << eo::setlevel(eo::debug);
eo::log << eo::warnings; eo::log << eo::warnings;
eo::log << "We are writing on the default output stream" << std::endl; eo::log << "We are writing on the default output stream" << std::endl;
eo::log << eo::file("test.txt") << "In FILE" << std::endl; {
eo::log << std::cout << "on COUT" << 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::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.addRedirect(oss);
eo::log << "In STRINGSTREAM";
std::cout << "Content of ostringstream: " << oss.str() << std::endl;
assert(oss.str() == "In STRINGSTREAM");
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("errors");
eo::log << eo::setlevel(eo::errors); eo::log << eo::setlevel(eo::errors);
@ -42,9 +90,8 @@ int main(int ac, char** av)
eo::log << std::endl; eo::log << std::endl;
eo::log << eo::debug << 4 << ')' eo::log << eo::debug << 4 << ')'
<< "4) in debug mode\n"; << "4) in debug mode\n";
return 0;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------