Boost logo

Boost :

From: John Eddy (johneddy_at_[hidden])
Date: 2005-02-15 12:00:15


Hello Darren,

I very much appreciate your feedback and will answer your questions as
best I can.

Darren Cook wrote:

>> I have continued working on a logging library as a possible contender
>> for a new Boost library.
>
>
> Hi,
> I just had a quick look. My usual logging needs are:
>
> 1. Being able to remove all logging code in a release build
> I see you have macros, though their names are long and it wasn't
> clear what all the different macros do (in examples/macros.cpp).
> Any issues in just doing a #define after including your headers
> to rename your macros into something short so I can simply write:
> LOG("In f, a="<<a<<",b="<<b);

You can easily remove all logging code from your release build by not
defining BOOST_LOGGING_ON. If you do that, all the headers wind up
doing nothing with the exception of the macro header which causes all
the macros to expand to nothing.

I agree that the macro names are long and a bit confusing. They all
resolve to nothing if BOOST_LOGGING_ON is not defined with the exception
of the BOOST_LOGGING_IF_OFF macro which I'm not sure is useful at all
anyway. The difference between the various *LOG* macros is the ability
to determine whether or not an entry will get logged before the entry is
actually created. If that can be done (which it can using the macros)
the process of logging in the case where it is common for log entries to
be rejected can become much cheaper.

If I continue to develop this as a possible boost library, I will of
course accept suggestions for renaming the macros and anything else for
that matter. I can see how something like BOOST_LOG() would be
simpler than BOOST_LOGGING_LOG() etc.

>
> 2. Logging with timestamp automatically prefixed. Do you have
> something pre-built for this? If not, can you show what code I have to
> write to implement it.
>
There is a "helper" for automatically putting a timestamp into an
entry. There are also a number of pre-existing entry types that are
implementing that helper and of course, I can create any others that you
might like. Below is an example of an entry that holds only a timestamp
along with any other text supplied to it. The constructor of the entry
takes a boost::posix_time::ptime object as the stamp (the default value
is the current time) and any leading text that you wish to associate
with the entry.

/*
 * This example shows how to use the basic timestamp entry.
 */

#include <iostream>
#include <boost/logging/logs/ostream_log.hpp>
#include <boost/logging/entries/timestamp_entry.hpp>
#include <boost/logging/log_managers/basic_log_manager.hpp>

using namespace std;
using namespace boost::logging;

int main(int argc, char* argv)
{
    ostream_log<> alog(cerr);
    basic_log_manager<ostream_log<> > alm(alog);

    alm.log(timestamp_entry<>("Hello. Its ")
                << timestamp_entry<>::stamp
                << ". Have a nice day."
                );
    return 0;
}

If you wanted the timestamp to be the very first thing, simply don't
supply anything to the timestamp entry constructor. ie
timestamp_entry<>() instead of timestamp_entry<>("Hello...

> 3. Logging with file, line number and/or function name included.

I have not built the facilities for this yet but I certainly plan to do
the file and line number at least. It is a fairly simple matter of
creating the proper entry helpers and implementing some entry types that
use them.

I would like to note that anything "stream-outable" can be inserted to
any of the basic_entry derivative types. The only thing that you get by
using the helpers is that the entry will store the information (such as
a timestamp) separately from the rest of the text so that it can be
recalled. This is so that entries can be searched or otherwise
differentiated based on their properties. Something as simple as the
file and line numbers using the macros __FILE__ and __LINE__ could be
inserted into any basic_entry right now so long as you don't wish to
query for entries based on that information in your code. So if you are
just printing this stuff to a file or other ostream or whatever and then
forgetting about it (in code anyway) you could replace the above with:

        alm.log(basic_entry<>("Hello. Its ")
                << boost::posix_time::microsec_clock::local_time()
                << " and we're in file " << __FILE__
                << " on line " << __LINE__
                << ". Have a nice day."
                );

>
> 4. Logging to an in-memory buffer that only stores e.g. the last 50K
> or the last 100 log lines; with a function to output the log to an
> ostream. (i.e. I want to add LOG() lines are the start of each
> function, and at certain other key points, and then output a history
> trace when something asserts).
> Do you have anything like this? If not which current component
> would you suggest I use as a starting point to modify?
>
This would be a matter of creating a new log type. Currently I have
implemented an ostream_log, file_log, list_log, appending_log,
decorator_log, and null_log. These are all fairly simple and I see the
need for many more log types. The only requirement of a log is that it
have a method called log that accepts a single entry parameter. The
method should probably be templatized but of course, it needn't be
depending on the types of things you are logging. The log managers will
accept the log type as the first template argument and use the log
method when appropriate.

To do what you want, I think you should plan to use the appending log
with your custom buffered log and an appender (callback) to output to a
stream - or the decorator log with your custom log as the first and an
ostream log as the second. Then each entry as it comes in would be
written into your custom log and then out to the ostream.

The decorator is fairly simple to use. For example, here is a decorator
for writing to cerr and to a file called "run.log".

ostream_log<> olog(cerr);
file_log<> flog("run.log");
decorator_log<ostream_log<>, file_log<> > dlog(olog, flog);

basic_log_manager<decorator_log<ostream_log<>, file_log<> > > alm(dlog);

Log whatever to alm as you normally would and it will wind up on
standard error and in run.log. To actually do this right now I noticed
that you will have to comment out the code in the constructor bodies of
the file log. I am in the process of getting rid of the exception
handling and so what's there won't compile.

>
> Darren
>
>> current state is available for simple download from
>> www.eng.buffalo.edu/~johneddy. It is not well Boost-ified yet but the
>
> _______________________________________________
> Unsubscribe & other changes:
> http://lists.boost.org/mailman/listinfo.cgi/boost


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