Classes | Defines
contrib/mul/mbl/mbl_log.h File Reference

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.

Detailed Description

Flexible and efficient status and error logging.

Author:
Ian Scott
Date:
16-Jan-2005 Good log statements are left in the code, and switched on or off at runtime. To make this feasible, the decision about whether to send a log message should be as efficient as possible. The runtime cost of a switched off mbl_log statement will be no more than an integer comparison, if you have a decent optimising compiler.

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 Documentation

#define MBL_LOG (   my_level,
  logger,
  message 
)
Value:
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.

Definition at line 370 of file mbl_log.h.