[Q]: What is the recommended logging facility for boost: log4cpp or ??

Hi I am wondering what is the logging facility recommended by the boost community: We are using log4cpp and are quite satified for now of its functionnalities. But as usual, it is a separate package, not anymore maintained and out of the boost foundry... What 's your opinion on this subjet?? Cheers Francis -- A good friend will come bail you out of jail.......... but, a true friend....will be sitting next to you saying: "...that was fun."

On Fri, 22 Oct 2004 12:38:03 +0200, Francis ANDRE <francis.andre@easynet.fr> wrote:
I am wondering what is the logging facility recommended by the boost community: We are using log4cpp and are quite satified for now of its functionnalities. But as usual, it is a separate package, not anymore maintained and out of the boost foundry...
I too would love to see a boost logging framework. We're using log4cplusplus here (different implementation than log4cpp but similar structure derived from log4j) and it has some nice features but some warts as well. Anyone interested in working on such a beast? It should be reasonably simple to write something with the new Boost.Iostreams facilities that have been reviewed recently. The must-have features for me are: * Uses iostreams * Thread-safe (e.g. two threads can't have their output intermixed in the output file/stream/whatever like they would with simple ostream<< operators) * Multiple possible output media (files, sockets, syslog, Windows event log, etc) * Multiple named channels each with configurable "threshold" (e.g. error, warning, debug, etc) * Messages which won't be logged shouldn't even go through the formatting step. I'm pretty sure this cannot be done in a single call w/o macros though. For example: BOOST_LOG (boost::log::debug, "This is a debug message: " << some_expensive_to_stream_class); Which would expand to something like: if (boost::log::is_enabled_for (boost::log::debug)) { ostringstream __os; os << "This is a debug message: " << some_expensive_to_stream_class; boost::log::force_write (boost::log::debug, os.str ()); } Anyone interested in working on this? -- Caleb Epstein caleb.epstein@gmail.com

Caleb Epstein wrote:
Anyone interested in working on such a beast?
There's been interest and discussion in the past. Search the archives and you should find some discussion and if I remember correctly some previous work on the subject.
It should be reasonably simple to write something with the new Boost.Iostreams facilities that have been reviewed recently. The must-have features for me are:
* Uses iostreams
I disagree. Like most things STL it should be independent of a stream back end. And ideally independent of a formatting front end. It should only be a tagging, filtering, and multiplexing interface.
* Thread-safe (e.g. two threads can't have their output intermixed in the output file/stream/whatever like they would with simple ostream<< operators)
Yes, but only if needed. It might not be appropriate depending on the front end or back end. For example you might be dumping the "output" to a database which would create individual debug records. No need for thread safety at the log level in that case.
* Multiple possible output media (files, sockets, syslog, Windows event log, etc)
Multiplexing.
* Multiple named channels each with configurable "threshold" (e.g. error, warning, debug, etc)
And configurable, so that you can program what each one does on both the front end and to which back end they go to.
* Messages which won't be logged shouldn't even go through the formatting step. I'm pretty sure this cannot be done in a single call w/o macros though. For example:
BOOST_LOG (boost::log::debug, "This is a debug message: " << some_expensive_to_stream_class);
Which would expand to something like:
if (boost::log::is_enabled_for (boost::log::debug)) { ostringstream __os; os << "This is a debug message: " << some_expensive_to_stream_class; boost::log::force_write (boost::log::debug, os.str ()); }
It's possible without macros for some compilers using careful template instaciations. For example the very simple logger I wrote uses syntax like so (and yes I prefer printf formatting :-)... log<RevisionLog>::trace( "RevisionControl::commit_; wait for ticket #%d",ticket); Because the formatting is done by the trace call, and the trace call is empty (and inlined) when the log is disabled, no formatting takes place. Something similar can be done regardless of what the formatting object is by having a specialization that does nothing. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

I have asked to the owner of log4cpp if he would be interested in putting log4cpp in the boost foundry (sandbox first for sure) with a change from the LGPL licence to the boost one. log4cpp is already packaged (somewhat) for multithreading. I think there should be a small effort to change its internal threading structure to the boost one and log4cpp has no strong adherence to any back iostream. Moreover, the documentation is already in place. In any case, I am volunter for spending some days of put boost::log4cpp in the boost foundry as a starting point, but I do not want to reinvent the wheel by starting a new package. IMHO, log4cpp is enough for now in term of functionalities. I am not saying to not add functionnalities later on, but just make log4cpp as it is today running well on boost first and then think about new functionnalities to add. I am already overloaded (and I think most of us also) thus keeping the focus on a utlity tool that is already a mature software is a good tradeoff between the need/buy/build options Francis -- A good friend will come bail you out of jail.......... but, a true friend....will be sitting next to you saying: "...that was fun." "Rene Rivera" <grafik.list@redshift-software.com> a écrit dans le message de news:417918F7.9090908@redshift-software.com...
Caleb Epstein wrote:
Anyone interested in working on such a beast?
There's been interest and discussion in the past. Search the archives and you should find some discussion and if I remember correctly some previous work on the subject.
It should be reasonably simple to write something with the new Boost.Iostreams facilities that have been reviewed recently. The must-have features for me are:
* Uses iostreams
I disagree. Like most things STL it should be independent of a stream back end. And ideally independent of a formatting front end. It should only be a tagging, filtering, and multiplexing interface.
* Thread-safe (e.g. two threads can't have their output intermixed in the output file/stream/whatever like they would with simple ostream<< operators)
Yes, but only if needed. It might not be appropriate depending on the front end or back end. For example you might be dumping the "output" to a database which would create individual debug records. No need for thread safety at the log level in that case.
* Multiple possible output media (files, sockets, syslog, Windows event log, etc)
Multiplexing.
* Multiple named channels each with configurable "threshold" (e.g. error, warning, debug, etc)
And configurable, so that you can program what each one does on both the front end and to which back end they go to.
* Messages which won't be logged shouldn't even go through the formatting step. I'm pretty sure this cannot be done in a single call w/o macros though. For example:
BOOST_LOG (boost::log::debug, "This is a debug message: " << some_expensive_to_stream_class);
Which would expand to something like:
if (boost::log::is_enabled_for (boost::log::debug)) { ostringstream __os; os << "This is a debug message: " << some_expensive_to_stream_class; boost::log::force_write (boost::log::debug, os.str ()); }
It's possible without macros for some compilers using careful template instaciations.
For example the very simple logger I wrote uses syntax like so (and yes I prefer printf formatting :-)...
log<RevisionLog>::trace( "RevisionControl::commit_; wait for ticket #%d",ticket);
Because the formatting is done by the trace call, and the trace call is empty (and inlined) when the log is disabled, no formatting takes place. Something similar can be done regardless of what the formatting object is by having a specialization that does nothing.
-- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Francis ANDRE wrote:
I have asked to the owner of log4cpp if he would be interested in putting log4cpp in the boost foundry (sandbox first for sure) with a change from the LGPL licence to the boost one.
To me, log4cpp seems way too complex and just modeled after the Java way. Of course, this is just my very subjective oppinion ;) Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

John Torjo wrote:
Francis ANDRE wrote:
I have asked to the owner of log4cpp if he would be interested in putting log4cpp in the boost foundry (sandbox first for sure) with a change from the LGPL licence to the boost one.
To me, log4cpp seems way too complex and just modeled after the Java way.
Of course, this is just my very subjective oppinion ;)
I agree.

John Torjo wrote:
Francis ANDRE wrote:
I have asked to the owner of log4cpp if he would be interested in putting log4cpp in the boost foundry (sandbox first for sure) with a change from the LGPL licence to the boost one.
To me, log4cpp seems way too complex and just modeled after the Java way.
Of course, this is just my very subjective oppinion ;)
I agree.
About complexity, I have no other reference in c++ except in house boring and tedious package...but using log4cpp was quite simple in term of integration. So I do not quite agree with the "complexity" argument.... On the "Java way", I do not matter if the design comes from Java ofrSmalltalk or Eiffel or whatsoever if it does the job!!!.

John> To me, log4cpp seems way too complex and just modeled after the Java way. Neal> I agree. Thirded. Here's a patch for the code in John's logging.zip which should improve portability. I've just built it by hand on Linux and run one of the simple test programs successfully. The changes involve: * Use Boost.Thread for all threading, mutex, and tss stuff (requires 1.32.0 or CVS) * Use boost::detail::atomic_count for the change_id counter * Use std::strftime for the prepend_time() format specifier I had to put in API-specific calls inside prepend_thread_id. Boost.Thread really ought to offer some way to get at the current thread ID. -- Caleb Epstein caleb.epstein@gmail.com

Caleb Epstein wrote: Thanks for the patch! One minor change: in functions.cpp line 218, that should be: if (0 != strftime (m_buffer, sizeof (m_buffer), m_format.c_str (), &m_tm)) (last arg is pointer)

John> To me, log4cpp seems way too complex and just modeled after the Java way. Neal> I agree.
Thirded.
Here's a patch for the code in John's logging.zip which should improve portability. I've just built it by hand on Linux and run one of the simple test programs successfully. The changes involve:
* Use Boost.Thread for all threading, mutex, and tss stuff (requires 1.32.0 or CVS)
Caleb Epstein wrote: thanks! The only reason I did not use boost.thread was because at the time I developed it, I couldn't build it as "static runtime".
* Use boost::detail::atomic_count for the change_id counter * Use std::strftime for the prepend_time() format specifier
I had to put in API-specific calls inside prepend_thread_id. Boost.Thread really ought to offer some way to get at the current thread ID.
Thanks for the patch! I'll try to update my lib, and re-post. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

Rene Rivera <grafik.list@redshift-software.com> writes:
It's possible without macros for some compilers using careful template instaciations.
For example the very simple logger I wrote uses syntax like so (and yes I prefer printf formatting :-)...
log<RevisionLog>::trace( "RevisionControl::commit_; wait for ticket #%d",ticket);
Because the formatting is done by the trace call, and the trace call is empty (and inlined) when the log is disabled, no formatting takes place. Something similar can be done regardless of what the formatting object is by having a specialization that does nothing.
That does not eliminiate any overhead that may exist due to evaluating the function arguments prior to making the call, nor any potential side effects of those expressions. Personally, having debugging log statements completely disappear from the source code in a release build is more comforting, even if it involves a macro. -- Chris

Chris Uzdavinis wrote:
Rene Rivera <grafik.list@redshift-software.com> writes:
It's possible without macros for some compilers using careful template instaciations.
For example the very simple logger I wrote uses syntax like so (and yes I prefer printf formatting :-)...
log<RevisionLog>::trace( "RevisionControl::commit_; wait for ticket #%d",ticket);
Because the formatting is done by the trace call, and the trace call is empty (and inlined) when the log is disabled, no formatting takes place. Something similar can be done regardless of what the formatting object is by having a specialization that does nothing.
That does not eliminiate any overhead that may exist due to evaluating the function arguments prior to making the call,
Compilers tend to eliminate unused code very effectively. And for most logging use cases you are only using already existing bindings (in the compiler SSA sense) as you are reflecting the state of your program. So no new code is getting generated.
nor any potential side effects of those expressions.
If you are in a situation where you have side effects of consequence, or any side effect for that matter, in you logging statements you have considerably more to worry about. I'd say a redesign of your code would be in order at that point.
Personally, having debugging log statements completely disappear from the source code in a release build is more comforting, even if it involves a macro.
It's comforting in an old style sense :-) But I prefer to limit macro use as it interferes with debugging. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

"Rene Rivera" wrote:
Compilers tend to eliminate unused code very effectively.
BCB doesn't. And what if logging code relies on debug only members/functions?
Personally, having debugging log statements completely disappear from the source code in a release build is more comforting, even if it involves a macro.
Very true.
It's comforting in an old style sense :-) But I prefer to limit macro use as it interferes with debugging.
Debug support w/o macros may not be useable in many real projects. /Pavel

That does not eliminiate any overhead that may exist due to evaluating the function arguments prior to making the call, nor any potential side effects of those expressions.
Personally, having debugging log statements completely disappear from the source code in a release build is more comforting, even if it involves a macro.
In my lib, you say something like: BOOST_LOG(gui) << "cursor at " << x << "," << y; You can, at run-time, enable and/or disable logs. Thus, the above is equivalent to: // pseudo-code if ( is_log_enabled(gui_log) ) log(gui_log) << "cursor at " << x << "," << y; Thus, the overhead of computing the string to output happens only if the log is enabled. I think this is much more flexible (than having a compile-time switch). Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

From: Chris Uzdavinis <chris@uzdavinis.com>
Rene Rivera <grafik.list@redshift-software.com> writes:
It's possible without macros for some compilers using careful template instaciations.
For example the very simple logger I wrote uses syntax like so (and yes I prefer printf formatting :-)...
log<RevisionLog>::trace( "RevisionControl::commit_; wait for ticket #%d",ticket);
Because the formatting is done by the trace call, and the trace call is empty (and inlined) when the log is disabled, no formatting takes place. Something similar can be done regardless of what the formatting object is by having a specialization that does nothing.
That does not eliminiate any overhead that may exist due to evaluating the function arguments prior to making the call, nor any potential side effects of those expressions.
Personally, having debugging log statements completely disappear from the source code in a release build is more comforting, even if it involves a macro.
There are also plenty of times in which you want logging available in release builds but you want minimal overhead when it is disabled. A macro helps there, too, by moving the evaluation of the argument list into the body of a conditional statement. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On Fri, 22 Oct 2004 17:16:14 -0400 (EDT), Rob Stewart wrote
From: Chris Uzdavinis <chris@uzdavinis.com>
Rene Rivera <grafik.list@redshift-software.com> writes:
It's possible without macros for some compilers using careful template instaciations.
For example the very simple logger I wrote uses syntax like so (and yes I prefer printf formatting :-)...
log<RevisionLog>::trace( "RevisionControl::commit_; wait for ticket #%d",ticket);
Because the formatting is done by the trace call, and the trace call is empty (and inlined) when the log is disabled, no formatting takes place. Something similar can be done regardless of what the formatting object is by having a specialization that does nothing.
That does not eliminiate any overhead that may exist due to evaluating the function arguments prior to making the call, nor any potential side effects of those expressions.
Personally, having debugging log statements completely disappear from the source code in a release build is more comforting, even if it involves a macro.
There are also plenty of times in which you want logging available in release builds but you want minimal overhead when it is disabled. A macro helps there, too, by moving the evaluation of the argument list into the body of a conditional statement.
Well, personally, I'd really like to try and go macro-less on the logging approach. I don't like macros because: 1) The logging code will be in the release build anyway (for all industrial apps I've seen this is the case). 2) Macro systems tend to be fragile -- pass it bad type (eg:string instead of char*) and it might crash your app. In this day and age the compiler should detect these errors... 3) I hate having to read macro code and then 'expand it mentally' -- I'm getting too dang old for it. Because of #1 I'd actually be fine if all the macro did was enable/disable so I it's use would effectively be optional. Jeff

Jeff Garland wrote:
Well, personally, I'd really like to try and go macro-less on the logging approach. I don't like macros because:
1) The logging code will be in the release build anyway (for all industrial apps I've seen this is the case).
Yes. The debug systems I've implemented or used all behave that way. My preferred method is to make log output depend on whether the LOG facility is available at runtime. That is if my log.dll/so is around or not. That level of configuration by end users is very easy for them to understand. Also logging is used for output other than debug output in system friendly programs. For example sending info when your server application starts and stops to syslog.
2) Macro systems tend to be fragile -- pass it bad type (eg:string instead of char*) and it might crash your app. In this day and age the compiler should detect these errors...
And macro systems are much harder to make work flexibly. It's much harder to change how a macro works than it is a function call without also changing all the code that uses the macros.
3) I hate having to read macro code and then 'expand it mentally' -- I'm getting too dang old for it.
Aren't we all ;-)
Because of #1 I'd actually be fine if all the macro did was enable/disable so I it's use would effectively be optional.
John's code is very close to that. If the code that his BOOST_LOG produces could be reduced to a simpler public interface so that those of us who don't want to use the macros can use instead, it would make it a winner for me. One important aspect of having a public macro-less interface, is that it would allow those with current log facilities (like me) to recode without changing all the logging calls. Which is a rather large task when you have a few million lines of code in your application :-\ -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

On Fri, 22 Oct 2004 17:27:06 -0500, Rene Rivera wrote
Also logging is used for output other than debug output in system friendly programs. For example sending info when your server application starts and stops to syslog.
Yes, exactly. There's usually a log_info category or something that doesn't get turned on/off by the level settings, macro expansion, etc.
John's code is very close to that. If the code that his BOOST_LOG produces could be reduced to a simpler public interface so that those of us who don't want to use the macros can use instead, it would make it a winner for me.
I haven't had time to look at his code yet :-(
One important aspect of having a public macro-less interface, is that it would allow those with current log facilities (like me) to recode without changing all the logging calls. Which is a rather large task when you have a few million lines of code in your application :-\
I'm not sure I understand -- are you saying you will integrate new logging into the same output stream without having to recompile all the existing code? BTW, one 'logging related' feature I would love to see is the stack snap that was discussed maybe 2 years back and has some prototypes in the files section. It would be wonderful to log a stack trace with data before throwing an exception. I realize it wouldn't be portable to all platforms, but it can be ported 'the major platforms' and it would be a huge boon to solving real-world problems in big software systems. Of course it could be a stand-alone lib too... Jeff

Jeff Garland wrote:
On Fri, 22 Oct 2004 17:27:06 -0500, Rene Rivera wrote
One important aspect of having a public macro-less interface, is that it would allow those with current log facilities (like me) to recode without changing all the logging calls. Which is a rather large task when you have a few million lines of code in your application :-\
I'm not sure I understand -- are you saying you will integrate new logging into the same output stream without having to recompile all the existing code?
In my case I have two options: a) Change my single Log.h header to use a new log facility directly. That would require a full recompile. b) Or I could change the implementation my log facilities, at my Log.cpp. This would not require a recompile as it would only change my log.dll. What I don't want to be forced to do is change every instance of log<*>::*(...) in all my code as it would literally take me weeks to do it, and to test it. Not that I'm saying it would not be possible for me to use something that is macro based. What I'm saying is that it's guaranteed to be possible to make that switch with a macro-less supporting solution. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

On Fri, 22 Oct 2004 18:31:14 -0500, Rene Rivera wrote
What I don't want to be forced to do is change every instance of log<*>::*(...) in all my code as it would literally take me weeks to do it, and to test it.
Not that I'm saying it would not be possible for me to use something that is macro based. What I'm saying is that it's guaranteed to be possible to make that switch with a macro-less supporting solution.
Got it... Jeff

Rene Rivera <grafik.list <at> redshift-software.com> writes:
John's code is very close to that. If the code that his BOOST_LOG produces could be reduced to a simpler public interface so that those of us who don't want to use the macros can use instead, it would make it a winner for me.
Hi Rene I've been writing/using a lib that librally borrows some of the techniques John was using, but I've separated the log object from the "manager" that handles the connection tables to suit my requirements better and hopefully to make it easier to plug in alternative approaches. I've kept the macro because the macro has the advantage of not even evaluating arguments to the expression/function call when a log is turned off. If you are prepared to forgo that, I think you can just repackage the interface. #define LOG(THE_LOG) \ if (logging::msg<logging::detail::manager> m = THE_LOG); else m.get_stream() becomes (for a printf interface): log_printf(logger &l, const char *fmt, ...) { logging::msg<logging::detail::manager> m = l; if (!m) { char buf[101]; va_list args; va_start(args, fmt); int n = vsnprintf (buf, 101, fmt, args)); va_end(args); if (n < 0) return; m.get_stream().write(buf, n > 100 ? 100 : n); } ) I guess for your static logs this would be wrapped up in a class template with a static logger instance and trace function, but that should be all it takes to limit the scope of changes?
One important aspect of having a public macro-less interface, is that it would allow those with current log facilities (like me) to recode without changing all the logging calls. Which is a rather large task when you have a few million lines of code in your application :-\
Fair enough! How many logs and how many sinks/appenders do you have/need for this application? Regards Darryl Green.

On Sat, 23 Oct 2004 07:10:48 +0000 (UTC), Darryl Green <darryl.green@unitab.com.au> wrote:
char buf[101]; va_list args; va_start(args, fmt); int n = vsnprintf (buf, 101, fmt, args)); va_end(args); if (n < 0) return;
This is one of the reasons I find the *snprintf functions to be pure evil. They don't return -1 when the output would be too long, they return the size they WOULD have written if the buffer was large enough. Is this code doing what you intend? -- Caleb Epstein caleb.epstein@gmail.com

Caleb Epstein wrote:
On Sat, 23 Oct 2004 07:10:48 +0000 (UTC), Darryl Green <darryl.green@unitab.com.au> wrote:
char buf[101]; va_list args; va_start(args, fmt); int n = vsnprintf (buf, 101, fmt, args)); va_end(args); if (n < 0) return;
This is one of the reasons I find the *snprintf functions to be pure evil. They don't return -1 when the output would be too long, they return the size they WOULD have written if the buffer was large enough.
That's not evil; it's extremely useful if you want to dynamically allocate a large enough buffer. All you have to do is check that the return value is less than or equal to the length you passed in. (Aside: what if the length is greater than INT_MAX?)
Is this code doing what you intend?
When built with Visual C++, it probably is. MS documents this function as returning a negative value in case of error. A portable test would be size_t(n) > sizeof(buf). Ben.

On Mon, 25 Oct 2004 14:17:11 +0100, Ben Hutchings <ben.hutchings@businesswebsoftware.com> wrote:
Caleb Epstein wrote:
On Sat, 23 Oct 2004 07:10:48 +0000 (UTC), Darryl Green <darryl.green@unitab.com.au> wrote:
char buf[101]; va_list args; va_start(args, fmt); int n = vsnprintf (buf, 101, fmt, args)); va_end(args); if (n < 0) return;
This is one of the reasons I find the *snprintf functions to be pure evil. They don't return -1 when the output would be too long, they return the size they WOULD have written if the buffer was large enough.
That's not evil; it's extremely useful if you want to dynamically allocate a large enough buffer. All you have to do is check that the return value is less than or equal to the length you passed in.
(Aside: what if the length is greater than INT_MAX?)
Is this code doing what you intend?
When built with Visual C++, it probably is. MS documents this function as returning a negative value in case of error. A portable test would be size_t(n) > sizeof(buf).
OK, perhaps it isn't *pure* evil, but I have seen lots of code that assumes *snprintf returns -1 when the buffer is too small. It doesn't, or at least not portably. I just think this behavior is confusing w/r/t the behavior of other standard library functions and leads to subtle program bugs, which is why I dislike this family of functions. -- Caleb Epstein caleb.epstein@gmail.com

Caleb Epstein <caleb.epstein <at> gmail.com> writes:
On Mon, 25 Oct 2004 14:17:11 +0100, Ben Hutchings <ben.hutchings <at> businesswebsoftware.com> wrote:
Caleb Epstein wrote:
On Sat, 23 Oct 2004 07:10:48 +0000 (UTC), Darryl Green <darryl.green <at> unitab.com.au> wrote:
char buf[101]; va_list args; va_start(args, fmt); int n = vsnprintf (buf, 101, fmt, args)); va_end(args); if (n < 0) return;
Well, it should probably log a logging failure ;-) at this point rather than silently doing nothing, but you also snipped the next line: m.get_stream().write(buf, n > 100 ? 100 : n); Which does the/a right thing when the snprintf worked but truncated the output. I am not suggesting this is tested, portable code. There may be broken snprintf's and I wrote that code in the gmane web interface - I have no idea if it even compiles. My intent was only to illustrate that it isn't hard to modify/extend the logging library for particular user requirements (not mine btw). Regards Darryl.

Ben Hutchings <ben.hutchings@businesswebsoftware.com> wrote: []
This is one of the reasons I find the *snprintf functions to be pure evil. They don't return -1 when the output would be too long, they return the size they WOULD have written if the buffer was large enough.
That's not evil; it's extremely useful if you want to dynamically allocate a large enough buffer. All you have to do is check that the return value is less than or equal to the length you passed in.
Man pages on my RH 9 AS say that a return value that is *equal* or greater than the size of the buffer means that the buffer is too small. That makes perfect sense because the function returns the number of characters written not including the null terminator, so if it returns a value equal to the size of the buffer than it did not have enough space for the null terminator, though the actual output in the buffer is null terminated.
When built with Visual C++, it probably is. MS documents this function as returning a negative value in case of error. A portable test would be size_t(n) > sizeof(buf).
Shouldn't it be size_t(n) >= sizeof(buf) ? -- Maxim Yegorushkin

Maxim Yegorushkin wrote:
Ben Hutchings <ben.hutchings@businesswebsoftware.com> wrote:
[]
This is one of the reasons I find the *snprintf functions to be pure evil. They don't return -1 when the output would be too long, they return the size they WOULD have written if the buffer was large enough.
That's not evil; it's extremely useful if you want to dynamically allocate a large enough buffer. All you have to do is check that the return value is less than or equal to the length you passed in.
Man pages on my RH 9 AS say that a return value that is *equal* or greater than the size of the buffer means that the buffer is too small.
Right, and that agrees with POSIX. I somehow misread the specification first time around. <snip>
Shouldn't it be
size_t(n) >= sizeof(buf)
?
Yes, it should. Ben.

Well, personally, I'd really like to try and go macro-less on the logging approach. I don't like macros because:
1) The logging code will be in the release build anyway (for all industrial apps I've seen this is the case). 2) Macro systems tend to be fragile -- pass it bad type (eg:string instead of char*) and it might crash your app. In this day and age the compiler should detect these errors...
It depends on how many macros you use. In my lib, there's only two: BOOST_LOG BOOST_IS_LOG_ENABLED If you look at the usage, any semantic error will be reported at compile-time. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Fri, 22 Oct 2004 17:16:14 -0400 (EDT), Rob Stewart wrote
There are also plenty of times in which you want logging available in release builds but you want minimal overhead when it is disabled. A macro helps there, too, by moving the evaluation of the argument list into the body of a conditional statement.
Well, personally, I'd really like to try and go macro-less on the logging approach. I don't like macros because:
1) The logging code will be in the release build anyway (for all industrial apps I've seen this is the case).
Some logging is debug only and really shouldn't be in the release build. If the mechanism makes the overhead nothing more than a Boolean test, without side effect argument evaluation, etc., you could leave it in. Even then, each of those conditionals might trigger a bad guess by early stages of a process pipeline, so it might have deleterious effects on performance.
2) Macro systems tend to be fragile -- pass it bad type (eg:string instead of char*) and it might crash your app. In this day and age the compiler should detect these errors...
If the macro does very little, such as produce a conditional followed by one line of code, there's not much room for this problem. It is also easy to see the definition of such a macro to understand how it works.
3) I hate having to read macro code and then 'expand it mentally' -- I'm getting too dang old for it.
If the macro is simple, there should be no problem, even for an old many like you. ;-)
Because of #1 I'd actually be fine if all the macro did was enable/disable so I it's use would effectively be optional.
It may be that the best approach is one that exposes two interfaces. One involves a macro that provides the smallest runtime overhead. The other might involve one or two C++ functions or types. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On Mon, 25 Oct 2004 14:41:31 -0400 (EDT), Rob Stewart <stewart@sig.com> wrote:
From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Fri, 22 Oct 2004 17:16:14 -0400 (EDT), Rob Stewart wrote
There are also plenty of times in which you want logging available in release builds but you want minimal overhead when it is disabled. A macro helps there, too, by moving the evaluation of the argument list into the body of a conditional statement.
Well, personally, I'd really like to try and go macro-less on the logging approach. I don't like macros because:
1) The logging code will be in the release build anyway (for all industrial apps I've seen this is the case).
Some logging is debug only and really shouldn't be in the release build. If the mechanism makes the overhead nothing more than a Boolean test, without side effect argument evaluation, etc., you could leave it in. Even then, each of those conditionals might trigger a bad guess by early stages of a process pipeline, so it might have deleterious effects on performance.
I find great utility in being able to leave debug-type logging statements in production code and enable them as-needed when the situation arises (e.g. through sending an extrnal signal or command to a process). This dictates that the "is_enabled" check be very inexpensive, and that when it fails the log message should not even be formatted.
2) Macro systems tend to be fragile -- pass it bad type (eg:string instead of char*) and it might crash your app. In this day and age the compiler should detect these errors...
If the macro does very little, such as produce a conditional followed by one line of code, there's not much room for this problem. It is also easy to see the definition of such a macro to understand how it works.
This is how the code John submitted works. A logging call looks like: BOOST_LOG (log_name) << the << things << to << output; not (as I've more commonly seen, and even done myself): LOG (log_name, the << stuff << to << output); or even (note multiple parens): ACE_LOG ((LM_INFO, "Some %glyph string", args ...)) I think John's approach is minimally intrusive and the usage of iostreams makes it pretty much impossible to mess anything up. I'm sure he can come up with a way that it can be used without macro as well (e.g. perhaps a boost::log method). As it stands now, it can be done but you'd be stuck with lines like: *(boost::log::log_id<log_stream_logid_type>::unique_id().m_stream) << some_message; Which is a lot harder to type than BOOST_LOG(log_stream) :-) I am not a fan of macros, and avoid them where possible, but I think they are the least painful solution to a problem like this one. -- Caleb Epstein caleb.epstein@gmail.com

I think John's approach is minimally intrusive and the usage of iostreams makes it pretty much impossible to mess anything up.
I'm sure he can come up with a way that it can be used without macro as well (e.g. perhaps a boost::log method). As it stands now, it can be done but you'd be stuck with lines like:
*(boost::log::log_id<log_stream_logid_type>::unique_id().m_stream) << some_message;
Which is a lot harder to type than BOOST_LOG(log_stream) :-)
I am not a fan of macros, and avoid them where possible, but I think they are the least painful solution to a problem like this one.
The main reason for requiring a macro was for efficiency, so that logging statements could easily be disabled. No matter what, you'll somehow need to do something like: // equivalent of: BOOST_LOG (some_log) << the << things << to << output; if ( is_enabled(some_log)) some_log << the << things << to << output; Which to me seems tedious and you can easily forget to write that. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

From: John Torjo <john.lists@torjo.com>
The main reason for requiring a macro was for efficiency, so that logging statements could easily be disabled.
No matter what, you'll somehow need to do something like:
// equivalent of: BOOST_LOG (some_log) << the << things << to << output;
if ( is_enabled(some_log)) some_log << the << things << to << output;
Which to me seems tedious and you can easily forget to write that.
Yes, something like that is necessary. I also agree that it is tedious and easily forgotten. The question is whether there is a way to capture that idea in such a way that it cannot be forgotten without adding additional overhead or tedium. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

No matter what, you'll somehow need to do something like:
// equivalent of: BOOST_LOG (some_log) << the << things << to << output;
if ( is_enabled(some_log)) some_log << the << things << to << output;
Which to me seems tedious and you can easily forget to write that.
Yes, something like that is necessary. I also agree that it is tedious and easily forgotten. The question is whether there is a way to capture that idea in such a way that it cannot be forgotten without adding additional overhead or tedium.
I'm certainly open to suggestions ;) I've thought about it for quite a while, and couldn't come up with a solution. If any of you has any idea about improving this, please speak up... Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

From: Caleb Epstein <caleb.epstein@gmail.com>
On Mon, 25 Oct 2004 14:41:31 -0400 (EDT), Rob Stewart <stewart@sig.com> wrote:
From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Fri, 22 Oct 2004 17:16:14 -0400 (EDT), Rob Stewart wrote
There are also plenty of times in which you want logging available in release builds but you want minimal overhead when it is disabled. A macro helps there, too, by moving the evaluation of the argument list into the body of a conditional statement.
Well, personally, I'd really like to try and go macro-less on the logging approach. I don't like macros because:
1) The logging code will be in the release build anyway (for all industrial apps I've seen this is the case).
Some logging is debug only and really shouldn't be in the release build. If the mechanism makes the overhead nothing more than a Boolean test, without side effect argument evaluation, etc., you could leave it in. Even then, each of those conditionals might trigger a bad guess by early stages of a process pipeline, so it might have deleterious effects on performance.
I find great utility in being able to leave debug-type logging statements in production code and enable them as-needed when the situation arises (e.g. through sending an extrnal signal or command to a process). This dictates that the "is_enabled" check be very inexpensive, and that when it fails the log message should not even be formatted.
Note that I said "some logging" is debug only. That is, it is specifically not wanted in the release build. I did not mean to imply that all "debug-type" logging should be compiled out. The point is that there should be a choice. Darren Cook's BOOST_LOG and BOOST_LOGD (though I'd name the latter, BOOST_LOG_DEBUG) permits the library user to choose whether to leave the logging in the release build or not.
2) Macro systems tend to be fragile -- pass it bad type (eg:string instead of char*) and it might crash your app. In this day and age the compiler should detect these errors...
If the macro does very little, such as produce a conditional followed by one line of code, there's not much room for this problem. It is also easy to see the definition of such a macro to understand how it works.
This is how the code John submitted works. A logging call looks like:
BOOST_LOG (log_name) << the << things << to << output;
Right. I was including John's version in that description, but it applies more generally. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

1) The logging code will be in the release build anyway (for all industrial apps I've seen this is the case).
Some logging is debug only and really shouldn't be in the release build. If the mechanism makes the overhead nothing more than a Boolean test, without side effect argument evaluation, etc., you could leave it in. Even then, each of those conditionals might trigger a bad guess by early stages of a process pipeline, so it might have deleterious effects on performance.
I agree. I frequently need logging code in an inner loop while trying to track down a problem. Hhhm, though I suppose I'll remove the log line once the bug is fixed anyway.
It may be that the best approach is one that exposes two interfaces. One involves a macro that provides the smallest runtime overhead. The other might involve one or two C++ functions or types.
I like this idea. E.g. from Caleb's next mail: BOOST_LOG (log_name) << the << things << to << output; BOOST_LOGD (log_name, the << things << to << output); where the LOGD version can be completely removed in a release build. Darren

I disagree. Like most things STL it should be independent of a stream back end. And ideally independent of a formatting front end. It should only be a tagging, filtering, and multiplexing interface.
internally, I use std::stringstream
* Thread-safe (e.g. two threads can't have their output intermixed in the output file/stream/whatever like they would with simple ostream<< operators)
Yes, but only if needed. It might not be appropriate depending on the front end or back end. For example you might be dumping the "output" to a database which would create individual debug records. No need for thread safety at the log level in that case.
indeed! that's what my lib does. You can choose to have a thread-safe writer, but only if you wish.
* Multiple possible output media (files, sockets, syslog, Windows event log, etc)
Multiplexing.
yup, we have that ;)
* Multiple named channels each with configurable "threshold" (e.g. error, warning, debug, etc)
And configurable, so that you can program what each one does on both the front end and to which back end they go to.
yup, we have that.
* Messages which won't be logged shouldn't even go through the formatting step. I'm pretty sure this cannot be done in a single call w/o macros though. For example:
BOOST_LOG (boost::log::debug, "This is a debug message: " << some_expensive_to_stream_class);
Which would expand to something like:
if (boost::log::is_enabled_for (boost::log::debug)) { ostringstream __os; os << "This is a debug message: " << some_expensive_to_stream_class; boost::log::force_write (boost::log::debug, os.str ()); }
yup, we have that.
It's possible without macros for some compilers using careful template instaciations.
In my case, there's one macro: BOOST_LOG. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

On Fri, 22 Oct 2004 20:22:46 +0200, John Torjo <john.lists@torjo.com> wrote:
yup, we have that. ^ nth power
Looks pretty nice. What about using std::strftime to provide the prepend_time functionality instead of the home-grown code with the $hh, $mm, etc specifiers? -- Caleb Epstein caleb.epstein@gmail.com

Trying this on linux/gcc. I tried to compile the basic test. I get: /disk1/nbecker/boost-root/boost/log/detail/ts.hpp:51: error: `LPCRITICAL_SECTION' does not name a type /disk1/nbecker/boost-root/boost/log/detail/ts.hpp:52: error: `CRITICAL_SECTION' does not name a type Is this by chance ms-windows specific?

Neal D. Becker wrote:
Trying this on linux/gcc. I tried to compile the basic test. I get:
/disk1/nbecker/boost-root/boost/log/detail/ts.hpp:51: error: `LPCRITICAL_SECTION' does not name a type /disk1/nbecker/boost-root/boost/log/detail/ts.hpp:52: error: `CRITICAL_SECTION' does not name a type
Is this by chance ms-windows specific?
sorry for that. see my other post (I used this since I was unsatisfied with boost.thread at that time) Again, I'll use Caleb Estein's changes, and re-post in a few days. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

On Sun, 24 Oct 2004 16:43:35 +0200, John Torjo <john.lists@torjo.com> wrote:
Again, I'll use Caleb Estein's changes, and re-post in a few days.
Epstein :-) Note also at least one mistake in my patch. The last argument in the call to strftime should be &m_tim not m_tm. I've attached a corrected version of the patch. -- Caleb Epstein caleb.epstein@gmail.com

On Mon, 25 Oct 2004 08:35:35 -0400, Caleb Epstein <caleb.epstein@gmail.com> wrote:
I've attached a corrected version of the patch.
... and here's the attachment. Sorry about that. -- Caleb Epstein caleb.epstein@gmail.com

Caleb Epstein wrote:
On Mon, 25 Oct 2004 08:35:35 -0400, Caleb Epstein <caleb.epstein@gmail.com> wrote:
I've attached a corrected version of the patch.
... and here's the attachment. Sorry about that.
Thanks, I'm applying the patch, and will submit very shortly (tomorrow or on Wed) Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

Anyone interested in working on this?
There is one: http://www.torjo.com/code/logging.zip I do have some more features to add. Unfortunately, been busy lately and did not get a chance to update. But in the current state, it should work quite smooth. It also contains some docs to get you started. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.5 - tooltips at your fingertips (work for menus too!) + bitmap buttons (work for MessageBox too!) + tab dialogs, hyper links, lite html

There are a couple of logging libs in the boost(yahoo) file area and in some more recent discussions John Torjo posted a promising lib with obvious boost ambitions at: www.torjo.com Regards // Fredrik Blomqvist Francis ANDRE wrote:
Hi
I am wondering what is the logging facility recommended by the boost community: We are using log4cpp and are quite satified for now of its functionnalities. But as usual, it is a separate package, not anymore maintained and out of the boost foundry...
What 's your opinion on this subjet??
Cheers
Francis
participants (15)
-
Ben Hutchings
-
Caleb Epstein
-
Chris Uzdavinis
-
Darren Cook
-
Darryl Green
-
Francis ANDRE
-
Fredrik Blomqvist
-
Jeff Garland
-
John Torjo
-
Maxim Yegorushkin
-
Neal Becker
-
Neal D. Becker
-
Pavel Vozenilek
-
Rene Rivera
-
Rob Stewart