Skip to content
Snippets Groups Projects
Commit 25842c88 authored by André Anjos's avatar André Anjos :speech_balloon:
Browse files

Implement proposed changes in C++ logging framework

parent d16c34a8
No related branches found
No related tags found
1 merge request!11Implement proposed changes in C++ logging framework
Pipeline #
...@@ -36,8 +36,21 @@ ...@@ -36,8 +36,21 @@
#include <bob.core/logging.h> #include <bob.core/logging.h>
// This static variable holds the current log level setting for all modules
static bob::core::LOG_LEVEL _CURRENT_LOG_LEVEL = bob::core::WARNING;
void bob::core::log_level(bob::core::LOG_LEVEL level) {
_CURRENT_LOG_LEVEL = level;
}
bob::core::LOG_LEVEL bob::core::log_level() {
return _CURRENT_LOG_LEVEL;
}
bob::core::OutputDevice::~OutputDevice() {} bob::core::OutputDevice::~OutputDevice() {}
struct NullOutputDevice: public bob::core::OutputDevice { struct NullOutputDevice: public bob::core::OutputDevice {
virtual ~NullOutputDevice() {} virtual ~NullOutputDevice() {}
virtual std::streamsize write(const char*, std::streamsize n) { virtual std::streamsize write(const char*, std::streamsize n) {
...@@ -45,6 +58,7 @@ struct NullOutputDevice: public bob::core::OutputDevice { ...@@ -45,6 +58,7 @@ struct NullOutputDevice: public bob::core::OutputDevice {
} }
}; };
struct StdoutOutputDevice: public bob::core::OutputDevice { struct StdoutOutputDevice: public bob::core::OutputDevice {
virtual ~StdoutOutputDevice() {} virtual ~StdoutOutputDevice() {}
virtual std::streamsize write(const char* s, std::streamsize n) { virtual std::streamsize write(const char* s, std::streamsize n) {
...@@ -57,6 +71,7 @@ struct StdoutOutputDevice: public bob::core::OutputDevice { ...@@ -57,6 +71,7 @@ struct StdoutOutputDevice: public bob::core::OutputDevice {
} }
}; };
struct StderrOutputDevice: public bob::core::OutputDevice { struct StderrOutputDevice: public bob::core::OutputDevice {
virtual ~StderrOutputDevice() {} virtual ~StderrOutputDevice() {}
virtual std::streamsize write(const char* s, std::streamsize n) { virtual std::streamsize write(const char* s, std::streamsize n) {
...@@ -69,6 +84,7 @@ struct StderrOutputDevice: public bob::core::OutputDevice { ...@@ -69,6 +84,7 @@ struct StderrOutputDevice: public bob::core::OutputDevice {
} }
}; };
/** /**
* Determines if the input filename ends in ".gz" * Determines if the input filename ends in ".gz"
* *
...@@ -123,36 +139,31 @@ struct FileOutputDevice: public bob::core::OutputDevice { ...@@ -123,36 +139,31 @@ struct FileOutputDevice: public bob::core::OutputDevice {
}; };
bool bob::core::debug_level(unsigned int i) {
const char* value = getenv("BOB_DEBUG");
if (!value) return false;
unsigned long v = strtoul(value, 0, 0);
if (v < 1 || v > 3) v = 0;
return (i <= v);
}
bob::core::AutoOutputDevice::AutoOutputDevice() bob::core::AutoOutputDevice::AutoOutputDevice()
: m_device(new NullOutputDevice) : m_level(bob::core::DISABLED), m_device(new NullOutputDevice)
{ {
} }
bob::core::AutoOutputDevice::AutoOutputDevice(const std::string& configuration) bob::core::AutoOutputDevice::AutoOutputDevice(const std::string& configuration,
: m_device() bob::core::LOG_LEVEL level)
: m_level(level), m_device()
{ {
reset(configuration); reset(configuration, level);
} }
bob::core::AutoOutputDevice::AutoOutputDevice(boost::shared_ptr<OutputDevice> d) bob::core::AutoOutputDevice::AutoOutputDevice(boost::shared_ptr<OutputDevice> d,
: m_device(d) bob::core::LOG_LEVEL level)
: m_level(level), m_device(d)
{ {
} }
bob::core::AutoOutputDevice::~AutoOutputDevice() { bob::core::AutoOutputDevice::~AutoOutputDevice() {
} }
void bob::core::AutoOutputDevice::reset(const std::string& configuration) void bob::core::AutoOutputDevice::reset(const std::string& configuration, bob::core::LOG_LEVEL level)
{ {
m_level = level;
std::string str(configuration); std::string str(configuration);
str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end()); str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
if (str == "null" || str.size()==0) m_device.reset(new NullOutputDevice); if (str == "null" || str.size()==0) m_device.reset(new NullOutputDevice);
...@@ -162,21 +173,32 @@ void bob::core::AutoOutputDevice::reset(const std::string& configuration) ...@@ -162,21 +173,32 @@ void bob::core::AutoOutputDevice::reset(const std::string& configuration)
} }
std::streamsize bob::core::AutoOutputDevice::write(const char* s, std::streamsize n) { std::streamsize bob::core::AutoOutputDevice::write(const char* s, std::streamsize n) {
return m_device->write(s, n); if (m_level >= _CURRENT_LOG_LEVEL) return m_device->write(s, n);
/* else */ return n;
} }
void bob::core::AutoOutputDevice::close() { void bob::core::AutoOutputDevice::close() {
m_level = bob::core::DISABLED;
m_device->close(); m_device->close();
} }
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::debug("stdout");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::info("stdout");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::warn("stderr");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::error("stderr");
void bob::core::log_level(bob::core::LOG_LEVEL level){ boost::iostreams::stream<bob::core::AutoOutputDevice>
bob::core::debug->reset(level == DEBUG ? "stdout" : "null"); bob::core::debug("stdout", bob::core::DEBUG);
bob::core::info->reset(level >= INFO && level < DISABLE ? "stdout" : "null"); boost::iostreams::stream<bob::core::AutoOutputDevice>
bob::core::warn->reset(level >= WARNING && level < DISABLE ? "stderr" : "null"); bob::core::info("stdout", bob::core::INFO);
bob::core::error->reset(level >= ERROR && level < DISABLE ? "stderr" : "null"); boost::iostreams::stream<bob::core::AutoOutputDevice>
bob::core::warn("stderr", bob::core::WARNING);
boost::iostreams::stream<bob::core::AutoOutputDevice>
bob::core::error("stderr", bob::core::ERROR);
bool bob::core::debug_level(unsigned int i) {
const char* value = getenv("BOB_DEBUG");
if (!value) return false;
unsigned long v = strtoul(value, 0, 0);
if (v < 1 || v > 3) v = 0;
return (i <= v);
} }
...@@ -26,6 +26,29 @@ ...@@ -26,6 +26,29 @@
*/ */
namespace bob { namespace core { namespace bob { namespace core {
/** enum defining levels of logs in C++;
they are the same as in the Python bindings, except for DISABLE, which is None in Python*/
typedef enum {
NOTSET = 0,
DEBUG = 10,
INFO = 20,
WARNING = 30,
ERROR = 40,
CRITICAL = 50,
DISABLED = 60,
} LOG_LEVEL;
/**
* brief This method will set up our default log streams to the given log
* level, or retrieve the currently set log-level
*
* warning: These functions should only be used in pure C++ code, as Python
* uses its own log level handling
*/
void log_level(LOG_LEVEL level);
LOG_LEVEL log_level();
/** /**
* @brief The device is what tells the sink where to actually send the * @brief The device is what tells the sink where to actually send the
* messages to. If the AutoOutputDevice does not have a device, the * messages to. If the AutoOutputDevice does not have a device, the
...@@ -72,20 +95,23 @@ namespace bob { namespace core { ...@@ -72,20 +95,23 @@ namespace bob { namespace core {
* *
* @param configuration The configuration string to use for this sink * @param configuration The configuration string to use for this sink
* as declared above * as declared above
*
* @param level The logging level to which this stream will output data.
* If the current globally set log level is bigger or equal than the
* level on the current stream, then we don't output data
*/ */
AutoOutputDevice(const std::string& configuration); AutoOutputDevice(const std::string& configuration, LOG_LEVEL level);
/** /**
* @brief Intializes with a device. * @brief Intializes with a device.
*/ */
AutoOutputDevice(boost::shared_ptr<OutputDevice> device); AutoOutputDevice(boost::shared_ptr<OutputDevice> device, LOG_LEVEL level);
/** /**
* @brief Updates with the given configuration; * @brief Updates with the given configuration;
* see constructor documentation for supported values * see constructor documentation for supported values
*/ */
void reset(const std::string& configuration); void reset(const std::string& configuration, LOG_LEVEL level);
/** /**
* @brief D'tor * @brief D'tor
...@@ -104,6 +130,7 @@ namespace bob { namespace core { ...@@ -104,6 +130,7 @@ namespace bob { namespace core {
private: private:
LOG_LEVEL m_level; ///< current output level set for this stream
boost::shared_ptr<OutputDevice> m_device; ///< Who does the real job. boost::shared_ptr<OutputDevice> m_device; ///< Who does the real job.
}; };
...@@ -125,24 +152,6 @@ namespace bob { namespace core { ...@@ -125,24 +152,6 @@ namespace bob { namespace core {
*/ */
bool debug_level(unsigned int i); bool debug_level(unsigned int i);
/** enum defining levels of logs in C++;
they are the same as in the Python bindings, except for DISABLE, which is None in Python*/
typedef enum {
ERROR = 0, // only errors are printed
WARNING = 1, // errors and warnings are printed
INFO = 2, // errors, warnings and info messages are printed
DEBUG = 3, // all messages are printed
DISABLE = 9 // no message is printed
} LOG_LEVEL;
/**
* brief This method will set up our default log streams to the given log level
*
* warning: This function should only be used in pure C++ code, as Python uses its own log level handling
*/
void log_level(LOG_LEVEL level=WARNING);
}} }}
//returns the current location where the message is being printed //returns the current location where the message is being printed
......
...@@ -188,7 +188,7 @@ static int set_stream(boost::iostreams::stream<bob::core::AutoOutputDevice>& s, ...@@ -188,7 +188,7 @@ static int set_stream(boost::iostreams::stream<bob::core::AutoOutputDevice>& s,
<< ") Resetting stream `" << n << "' to stderr" << std::endl; << ") Resetting stream `" << n << "' to stderr" << std::endl;
#endif #endif
s.close(); s.close();
s.open("stderr"); s.open("stderr", bob::core::DISABLED);
return 1; return 1;
} }
...@@ -204,7 +204,11 @@ static int set_stream(boost::iostreams::stream<bob::core::AutoOutputDevice>& s, ...@@ -204,7 +204,11 @@ static int set_stream(boost::iostreams::stream<bob::core::AutoOutputDevice>& s,
#endif #endif
s.close(); s.close();
s.open(boost::make_shared<PythonLoggingOutputDevice>(o, n)); //we set the stream to output everything to the Python callable by
//setting the log-level of the stream to the highest possible value.
//it is the job of the python logging system to figure out if the data
//should be output or not.
s.open(boost::make_shared<PythonLoggingOutputDevice>(o, n), bob::core::DISABLED);
return 1; return 1;
} }
} }
......
...@@ -212,18 +212,22 @@ class StringStreamOutputDevice: public boost::iostreams::sink { ...@@ -212,18 +212,22 @@ class StringStreamOutputDevice: public boost::iostreams::sink {
public: public:
StringStreamOutputDevice(boost::shared_ptr<std::stringstream> d) StringStreamOutputDevice(boost::shared_ptr<std::stringstream> d,
: m_buffer(d) { } bob::core::LOG_LEVEL level) : m_buffer(d), m_level(level) { }
virtual ~StringStreamOutputDevice() { } virtual ~StringStreamOutputDevice() { }
virtual std::streamsize write(const char* s, std::streamsize n) { virtual std::streamsize write(const char* s, std::streamsize n) {
if (m_buffer) m_buffer->write(s, n); if (m_buffer && should_log()) m_buffer->write(s, n);
return n; return n;
} }
virtual void close() { m_buffer.reset(); } virtual void close() { m_buffer.reset(); }
bool should_log() const {
return m_level >= bob::core::log_level();
}
private: private:
boost::shared_ptr<std::stringstream> m_buffer; boost::shared_ptr<std::stringstream> m_buffer;
bob::core::LOG_LEVEL m_level;
}; };
...@@ -250,12 +254,12 @@ BOB_TRY ...@@ -250,12 +254,12 @@ BOB_TRY
//pointers to those streams. //pointers to those streams.
boost::shared_ptr<std::stringstream> out(new std::stringstream("")); boost::shared_ptr<std::stringstream> out(new std::stringstream(""));
boost::shared_ptr<std::stringstream> err(new std::stringstream("")); boost::shared_ptr<std::stringstream> err(new std::stringstream(""));
boost::iostreams::stream<StringStreamOutputDevice> debug(out); boost::iostreams::stream<StringStreamOutputDevice> debug(out, bob::core::DEBUG);
boost::iostreams::stream<StringStreamOutputDevice> info(out); boost::iostreams::stream<StringStreamOutputDevice> info(out, bob::core::INFO);
boost::iostreams::stream<StringStreamOutputDevice> warn(err); boost::iostreams::stream<StringStreamOutputDevice> warn(err, bob::core::WARNING);
boost::iostreams::stream<StringStreamOutputDevice> error(err); boost::iostreams::stream<StringStreamOutputDevice> error(err, bob::core::ERROR);
//equivalent to: bob::core::log_level(bob::core::DEBUG); bob::core::log_level(bob::core::DEBUG);
debug << "This is a debug message" << std::endl; debug << "This is a debug message" << std::endl;
info << "This is an info message" << std::endl; info << "This is an info message" << std::endl;
warn << "This is a warning message" << std::endl; warn << "This is a warning message" << std::endl;
...@@ -263,12 +267,9 @@ BOB_TRY ...@@ -263,12 +267,9 @@ BOB_TRY
_test(out->str(), "This is a debug message\nThis is an info message\n", "debug"); _test(out->str(), "This is a debug message\nThis is an info message\n", "debug");
_test(err->str(), "This is a warning message\nThis is an error message\n", "debug"); _test(err->str(), "This is a warning message\nThis is an error message\n", "debug");
//equivalent to: bob::core::log_level(bob::core::ERROR); bob::core::log_level(bob::core::ERROR);
out->str(""); out->str("");
err->str(""); err->str("");
debug->close();
info->close();
warn->close();
debug << "This is a debug message" << std::endl; debug << "This is a debug message" << std::endl;
info << "This is an info message" << std::endl; info << "This is an info message" << std::endl;
warn << "This is a warning message" << std::endl; warn << "This is a warning message" << std::endl;
...@@ -276,10 +277,9 @@ BOB_TRY ...@@ -276,10 +277,9 @@ BOB_TRY
_test(out->str(), "", "error"); _test(out->str(), "", "error");
_test(err->str(), "This is an error message\n", "error"); _test(err->str(), "This is an error message\n", "error");
//equivalent to: bob::core::log_level(bob::core::DISABLE); bob::core::log_level(bob::core::DISABLED);
out->str(""); out->str("");
err->str(""); err->str("");
error->close();
debug << "This is a debug message" << std::endl; debug << "This is a debug message" << std::endl;
info << "This is an info message" << std::endl; info << "This is an info message" << std::endl;
warn << "This is a warning message" << std::endl; warn << "This is a warning message" << std::endl;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment