1. Edd Dawson
  2. blah

Wiki

Clone wiki

blah / Home

blah

blah is a stupid little C++ logging library. But that's fine. I tend to like my libraries stupid and little.

It's really quite customizable, though. You'll like it.

Key features

  • Deliberately small and stupid. Compare and contrast with log4cxx, for example.
  • You can define "transient" logs. The effects of using a transient log are completely absent from compiled code when you #define BLAH_DISABLE_TRANSIENT_LOGS.
  • Add/remove filters to change and redirect output, or invoke other side effects when data is logged
  • Each filter has access to lots of information such as the source file and line number of the log statement, as well as details of the thread in which the statement was executed and the date and time the statement was last compiled.
  • it should be very portable. It's certainly fine on Windows and Mac OS X.

Example code

Typical use would be to create a header that uses blah to define your logs. For example:

// mylogs.hpp
#include <blah.hpp>

#define DBG BLAH_TRANSIENT_LOG("dbg")
#define MSG BLAH_PERMANENT_LOG("msg")

Now in your code:

#include "mylogs.hpp"

DBG << "something that might be useful for debugging" << 42 << "etc";
MSG << "Status message, perhaps recorded somewhere for customer support";

Transient logs

As you can see, DBG and MSG can be treated like std::ostreams for the most part. Usually, that's what they are. The only thing you can't do is call their member functions:

DBG.precision(4); // please don't

When BLAH_DISABLE_TRANSIENT_LOGS is defined, DBG is no longer an std::ostream, it's just a black hole whose operator<< calls can be optimized away to nothing.

Note that DBG was defined using BLAH_TRANSIENT_LOG while MSG was defined using BLAH_PERMANENT_LOG. Stuff written to MSG will always be recorded, regardless of whether or not BLAH_DISABLE_TRANSIENT_LOGS is defined.

Perhaps we could change mylogs.hpp to this:

// mylogs.hpp

#if defined(NDEBUG)
    #define BLAH_DISABLE_TRANSIENT_LOGS
#endif
#include <blah.hpp>

#define DBG BLAH_TRANSIENT_LOG("dbg")
#define MSG BLAH_PERMANENT_LOG("msg")

Now in release builds (those that define NDEBUG while compiling), any statement that writes to DBG will be removed.

On good compilers such as recent versions of Microsoft Visual C++ and g++, "removed" means such statements will be compiled out completely. The assembly code will be the same as if the statement wasn't there in the first place, provided you turn on your compiler's optimiz0r. On lesser compilers, it means that it will do nothing extremely quickly.

Sensible defaults

By default, writing to our DBG and MSG logs will write stuff to std::clog with some useful decorations:

Consider this program:

#include <blah.hpp>

#define MSG BLAH_PERMANENT_LOG("msg")

int main()
{
    MSG << "Hello, world! " << 42;
    MSG << "Toodle-oo, world!";
    return 0;
}

The output would be something like:

[27 Mar 2009 20:51:44 | msg]: Hello, world! 42
[27 Mar 2009 20:51:44 | msg]: Toodle-oo, world!

You'll note the name of the log, "msg" is present in the output. What you might not be able to tell from this example is that by default, a newline will be added to the end of any log statement that doesn't already have one.

I spit on your definition of "sensible defaults"

Ok, so those defaults might not do what you have in mind.

If you want to learn about how to decorate, modify, redirect or block output then I'd suggest reading more about filters.

The other customization point that blah provides is the logger interface. You're probably better off writing filters, but take a look at what a logger is if you want the whole story.

Updated