Flexible and efficient status and error logging. More...
#include <vcl_fstream.h>
#include <vcl_streambuf.h>
#include <vcl_string.h>
#include <vcl_ostream.h>
#include <vcl_set.h>
#include <vcl_map.h>
#include <vcl_ios.h>
Go to the source code of this file.
Classes | |
class | mbl_log_streambuf |
Allows stream-like syntax on logger. More... | |
class | mbl_log_null_streambuf |
A null streambuf ignores all input. More... | |
class | mbl_log_output_base |
Base class for destinations of a logging event. More... | |
class | mbl_log_output_stream |
Outputs log messages to an existing stream (e.g. vcl_cerr). More... | |
class | mbl_log_output_file |
Outputs log messages to a named file. More... | |
class | mbl_logger |
Main user logging class - represents a category. More... | |
class | mbl_log_categories |
This class handles category lists. More... | |
struct | mbl_log_categories::cat_spec |
class | mbl_logger_root |
Singleton, keeps records of logging state. More... | |
Defines | |
#define | MBL_LOG(my_level, logger, message) |
Log a message. |
Flexible and efficient status and error logging.
These classes are patterned after the log4j logging library, although without all of the sophistication. (We have not copied any code from log4j (or other logging libraries) - just the ideas.)
To send a message to the log you need to do two things - create a logger object, and send a message to it. By creating a logger, you identify a category of logging events. You should create a separate category for each module of your program. However, creating loggers may not be cheap - so it is best not to do it too often.
mbl_logger my_log("imorphics.easy_stuff.does_halt");
The easiest way to send a log message looks like:
MBL_LOG(WARN, my_log, "Infinite loop: Time wasted so far " << time() );
The system will have been setup to assign a log level to a particular category. The log levels are EMERG < ALERT < CRIT < ERR < WARN < NOTICE < INFO < DEBUG. The above log message will be sent if the level for category "imorphics.easy_stuff.does_halt" is set to WARN or higher. You can avoid using macros by calling the logger directly
my_log.log(mbl_logger::WARN) << "Infinite loop: Time wasted so far " << time() << vcl_endl;
The vcl_endl (or a vcl_flush) is necessary to terminate the log line. The problem with this explicit version is that the stream insertion and call to the time() function take place, even if the logging level is set below WARN. Ideally, we would like unsent log messages to take as little time as possible - so that there is no overhead in leaving the log message in your code. To achieve this we can test the log level first
if (my_log.level() >= mbl_logger::WARN) my_log.log(mbl_logger::WARN) << "Infinite loop: Time wasted so far " << time() << vcl_endl;
Of course, you should just use MBL_LOG which handles this for you. Additionally MBL_LOG sorts out termination of the log message without using vcl_endl, allowing you to send multi-line messages in a single log output.
You can also use the logger to control the dumping of data files straight to the filesystem.
if (my_log.level() >= mbl_logger::INFO && my_log.dump()) { vcl_string filename=my_log.dump_prefix()+"my_image.png"; if (vil_save(my_image, filename.c_str())) MBL_LOG(INFO, my_log, "Saved my_image to " << filename); else MBL_LOG(ERR, my_log, "Failed to save my_image to " << filename); }
You can find all logger names in all source code in some subtree using the following command:
find . -type f | fgrep -v /.svn/ | xargs perl -ne 'print if s/.*\bmbl_logger(\s+\w+)?\s*\(\"(.*)\"\).*/$2\n/;' | sort -u
Definition in file mbl_log.h.
#define MBL_LOG | ( | my_level, | |
logger, | |||
message | |||
) |
do { mbl_logger &rlogger = logger; \ if (rlogger.level() >= mbl_logger:: my_level) {\ rlogger.mtstart(mbl_logger:: my_level, __FILE__, __LINE__); \ vcl_ios_fmtflags flags=rlogger.mtlog().flags(); \ vcl_streamsize precision=rlogger.mtlog().precision(); \ vcl_streamsize width=rlogger.mtlog().width(); \ rlogger.mtlog() << message << vcl_endl; \ rlogger.mtlog().width(width); \ rlogger.mtlog().precision(precision); \ rlogger.mtlog().flags(flags); \ rlogger.mtstop(); } \ } while (false)
Log a message.
This macro wraps up normal uses of the logger efficiently in source code-length and run-time.
MBL_LOG(DEBUG, my_logger, "time: " << time() << "\nstatus: " << my_data);
No function evaluations (e.g. of time() ) will take place unless the logger is enabled. The logger will also work correctly even if operator<<(my_data_t&)
flushes the stream.