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:
Johann Dréo <johann.dreo@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 <iostream>
#include <algorithm> // std::find
#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()
{
_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
@ -55,10 +62,11 @@ void eoLogger::_init()
addLevel("logging", eo::logging);
addLevel("debug", eo::debug);
addLevel("xdebug", eo::xdebug);
}
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'),
@ -66,33 +74,17 @@ eoLogger::eoLogger() :
_selectedLevel(eo::progress),
_contextLevel(eo::quiet),
_fd(2),
_obuf(_fd, _contextLevel, _selectedLevel)
_obuf(_contextLevel, _selectedLevel)
{
std::ostream::init(&_obuf);
std::ostream::init(&_obuf);
_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()
{
if (_fd > 2) { ::close(_fd); }
if (_obuf._ownedFileStream != NULL) {
delete _obuf._ownedFileStream;
}
}
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() )
{
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() )
@ -163,12 +157,6 @@ eoLogger& operator<<(eoLogger& l, const eo::Levels lvl)
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)
{
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)
{
if (l._standard_io_streams.find(&os) != l._standard_io_streams.end())
{
l._fd = l._standard_io_streams[&os];
}
#warning deprecated
l.addRedirect(os);
return l;
}
eoLogger::outbuf::outbuf(const int& fd,
const eo::Levels& contexlvl,
void eoLogger::redirect(std::ostream& 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);
}
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)
: _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)
{
if (_selectedLevel >= _contextLevel)
{
if (_fd >= 0 && c != EOF)
{
::write(_fd, &c, 1);
}
}
{
for (StreamIter it = _outStreams.begin(); it != _outStreams.end(); it++)
{
if (c != EOF)
{
(**it) << (char) c;
}
}
}
return c;
}
namespace eo
{
file::file(const std::string f)
: _f(f)
{}
setlevel::setlevel(const std::string v)
: _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; -*-
/*
(c) Thales group, 2010
This library is free software; you can redistribute it and/or
@ -22,6 +23,7 @@ Contact: http://eodev.sourceforge.net
Authors:
Johann Dréo <johann.dreo@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.
Here's an example explaning how to use eoLogger:
\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
For an example explaning how to use eoLogger, please refer to paradiseo/eo/test/t-eoLogger.cpp
@{
*/
@ -91,10 +44,23 @@ Caner Candan <caner.candan@thalesgroup.com>
#include <vector>
#include <string>
#include <iosfwd>
#include <fstream>
#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 <set>
#endif
namespace eo
{
/**
@ -110,16 +76,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.
@ -145,7 +101,7 @@ public:
eoLogger();
//! overidded ctor in order to instanciate a logger with a file define in parameter
eoLogger(eo::file file);
//eoLogger(eo::file file);
//! dtor
~eoLogger();
@ -180,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
@ -188,11 +150,19 @@ private:
class outbuf : public std::streambuf
{
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:
virtual int overflow(int_type c);
private:
const int& _fd;
const eo::Levels& _contextLevel;
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
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.
*/
@ -223,12 +187,39 @@ public:
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&);
/**
* 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:
friend void make_verbose(eoParser&);
@ -243,13 +234,7 @@ private:
eo::Levels _contextLevel;
/**
* _fd in storing the file descriptor at this place we can disable easily the buffer in
* 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.
* _obuf std::ostream mandates to use a buffer. _obuf is a outbuf inheriting from std::streambuf.
*/
outbuf _obuf;

View file

@ -3,30 +3,78 @@
//-----------------------------------------------------------------------------
#include <eo>
//#include <paradiseo/eo.h>
#include <fstream>
#include <sstream>
#include <string>
#include <cassert>
//-----------------------------------------------------------------------------
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 << 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(eo::errors);
@ -42,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";
}
//-----------------------------------------------------------------------------