Boost logo

Boost :

From: Jesse Jones (jesjones_at_[hidden])
Date: 2001-11-24 18:04:56

At 4:11 PM -0500 11/24/01, David A. Greene wrote:
>Jesse Jones wrote:
>>>I've written a class template that takes as template
>>>value parameter the number of streams logging messages
>>>should go to.
>> Personally I don't like using iostreams for debug logging. I
>> experimented with this with CodeWarrior Pro 6 (I think it was) and
>> got insane amounts of bloat.
>I haven't noticed such problems, though admittedly I haven't
>looked for them either. :)

The CodeWarrior IDE shows you the object and data sizes for each
file. I like this a lot, but it does mean that template bloat really
sticks out.

>I find iostreams much too convenient
>to just dismiss them out-of-hand. Often I want to dump the
>state of some object and iostreams is the only way to do it

Not true. Instead of providing an overloaded operator<< you can
provide an overloaded ToStr. About the only real difference is that
the ToStr functions can take optional arguments so you don't have to
use that godawful manipulator stuff to modify the formatting.

> >>Each stream can be bound to a different
>>>ostream, and each stream has its own threshold (to
>>>prioritize logging messages).
>> I do this a bit differently. When clients want to log something they
>> can specify a logging category (eg LOG("Sockets", "Sent ", bytes, "
>> bytes to ", address, ".\n")). When LOG is called it assembles the
>> string (using overloaded ToStr functions) and passes the string and
>> the category to the logger.
>Here is where I find iostreams nice to use. My simple debug
>macro is used like this:
>DEBUG("Sent " << bytes << " bytes to " << address, <other_args>);
>where <other_args> includes categories, levels, etc.

That part is nice. My system relies on overloaded LOG functions that
each take a different number of arguments so I have trouble sticking
in optional arguments. Currently if the user wants to log something
and not use a category they have to pass in NULL or "" for the first

>I haven't
>implemented anything beyond a simple global debug level since
>I didn't want to spend all my time writing debugging code. This
>is one of the reasons I asked whether Boost might provide such
>facilities. :)

It's pretty darn easy to do this.

> > The nice thing about this is that it's simple to use, messages are
>> filtered with a meaningful name instead of a number, there's no bloat
>> yet it's still type safe and extensible, and it can be easily
>> customized with different sinks.
>How do you specify different sinks?

The Log singleton has an AddSink method. Normally in main the client
code will add a few of the provided sinks (or perhaps a custom sink).
Something like this:

    Log::Instance()->AddSink(new StdErrSink);

> Is LOG a vararg macro?

Overloaded functions. Something like this:

    inline void LOG(const char* c, const std::string& s)
    {Log::Instance()->Write(c, s.c_str());}

    template <typename A1>
    inline void LOG(const char* c, const A1& a1)
    {LOG(c, ToStr(a1));}

    template <typename A1, typename A2>
    inline void LOG(const char* c, const A1& a1, const A2& a2)
    {LOG(c, ToStr(a1) + ToStr(a2));}

>I don't know why, but I feel a bit uncomfortable channelling
>based on a string. You're right in that it gives you a
>friendlier category tag than a number, but there's something
>that just doesn't "feel" right to me.

I think it's way better than relying on a number. It gives you more
control about what gets streamed out and it fits in nicely with GUI
apps where you can stick the categories in a menu so that you can
toggle them on and off at runtime (and hopefully store the state away
in a pref as well).

>Maybe it's that the
>compiler can't check whether a valid channel is being specified.

There's no such thing as an invalid category. When a new one is
encountered the category table is updated and the category starts out

   -- Jesse

Boost list run by bdawes at, gregod at, cpdaniel at, john at