Boost logo

Boost :

From: Jesse Jones (jesjones_at_[hidden])
Date: 2001-11-26 15:32:24


At 2:30 PM -0500 11/26/01, David A. Greene wrote:
>Jesse Jones wrote:
>
>>>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
>>>nicely.
>>
>> 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.
>
>But printf-like format strings are a big source of bugs.

Yep, but that's not a problem with ToStr. Consider this code:

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

This is fully as type safe and customizable as iostreams...

>I don't use optional arguments, actually. I haven't written
>anything that advanced yet. :) I'm curious -- how do you get
>line number information? Do you have to pass __LINE__ to the
>function? I've always hated the fact that we can't make template
>functions "inline-aware" and have __LINE__/__FILE__ reflect the
>line number where the template is inlined and not the line number
>of the template source file (yeah, yeah, stupid preprocessor...).

There's no support for line numbers. I haven't seen a need for
anything like that. The output is exactly what the user sent except
that log category names may be optionally prepended to each line and
the log singleton has a WriteTimeStamp method that writes out the
current time and date to the sinks.

> >>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.
>
>
>Oh, I know it is. But the fact the everyone and their mother
>does it seems to me to make a good case for a convenient library.
>
>Exactly _because_ it is simple makes a good case.

Maybe.

> >>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);
>
>
>Right, but how does LOG know which sink to send the message to?

LOG sends the assembled string to every enabled sink.

>Are categories bound to sinks?

No, the string is assembled, the logger checks to see if the category
is enabled, if it is the sinks get the assembled strings.

> From your usage in the previous message, it looks like each
>variable in the message is passed as a separate parameter. Doesn't
>that require a whole lot of overloaded methods?

Currently I support LOG functions with up to 10 custom arguments so I
have just over 10 overloaded functions. (Actually I have another 10
because there's a debug only version called TRACE).

> >>I don't know why, but I feel a bit uncomfortable channelling
>>>based on a string.
>
>
>> 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).
>
>
>An enum would work almost as well, but as I said, I can't put my
>finger on it. I can't think of a terribly good argument _not_
>to use a string.

I don't think so. The problem with an enum is that you have to define
all the categories up front. With a string you can link against the
UberLibrary and the logger (and perhaps a Log menu) will automagicly
become aware of the new "Uber" log category.

> >>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
> > disabled.
>
>Of course the presents the (probably likely) chance that the programmer
>will mis-type the category in some message and never see it (since he
>doesn't know the name of the category to turn on). Though inn a
>GUI he will at least get some strange menu entries. :)

Yep, and it is pretty obvious in a GUI app. In other apps I think
you'd still want to do something similar. For example, in the past
I've had app's that wrote the categories to an XML file on shutdown
and read from that file on startup. This way everyone on the team
could easily customize the logging output for the stuff they were
interested in. This isn't as in your face as a menu, but I think
misspelled categories would still be found fairly quickly.

   -- Jesse


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk