Boost Logging Lib, v2 - added documentation

J

jtorjo2007

Hi all,

I've added documentation for the Logging Lib v2 :
http://torjo.com/log2/ (Logging homepage)
http://torjo.com/log2/doc/html/ (documentation)

Just to make surem the Boost Log Library has these features:

* A simple and clear separation of concepts
o concepts are also easily separated into namespaces
* A very flexible interface
* You don't pay for what you don't use.
* Fits a lot of scenarios: from very simple (dumping all to one
log) to very complex (multiple logs, some enabled/some not, levels,
etc).
* Allows you to choose how you use logs in your code (by defining
your own LOG_ macros, suiting your application)
* Allows you to use Log levels (debug, error, fatal, etc). However
this is an orthogonal concept - the library will work whether you use
levels, categories or whatever , or not.
* Efficient filtering of log messages - that is, if a log is
turned off, the message is not processed at all
* Thread-safe - the library allows you several degrees of thread-
safety, as you'll see
* Allows for formatters and destinations
o formatters format the message (like, prepending extra
information - an index, the time, thread is, etc)
o destinations specify where the message is to be written
o Formatters and Destinations are orthogonal to the rest of
the library - if you want you can use them, otherwise you can define
your own writing mechanism
* Easy manipulation of the logs (turning on/off, setting
formatters, destinations, etc)

Feedback is most welcome - you can write to me directly - see
http://torjo.com/
for contact address.

{ Keeping the discussion in [comp.lang.c++.moderated] could benefit the
community, ref. FAQ item 5.4. -mod }

Best,
John
 
N

Neal E. Coombes


It may go without saying that I like my logging libraries policy
based! In 2005 I wrote the toast logging library (released open
source last month, see http://toast.sourceforge.net/group__loggroup.html),
which actually shares a lot of similarities to what you've got. So
for that I'm fairly happy with what you've produced. There are some
goals that I tried to achieve when designing toast::log that I would
also like to be met by any logger that eventually makes it in to
boost.

It is very often useful for a library to log things that are going on
behind the scenes. It would be useful if there was a unified
interface that libraries could rely on to do so. However, generally
it is not the library that should decide how logging is going to
actually happen. The logs themselves should be owned and configured
by the application and simply used by the libraries in a standard
way. Since your process_msg_type determines the interface of how to
log, no library would be able to rely on there being a unified
interface. This is the motivation for the toast::log::log_handle
class. Unfortunately this requirement makes your concept of gathering
(which I like) more difficult to implement. Obviously there is a run
time penalty for the type erasure, but it is a much smaller penalty
than having to recompile all your libraries whenever you change your
concrete logger, and there is no penalty at all for the application
directly. I could have also done this with a base class and virtual
functions, but I didn't want to require the use of pointers and
virtual functions.

So ultimately what I would propose as a change for your library is to
have a basic interface, that can be relied upon to always remain the
same, which you can build facades on top of for the convenience of the
clients actually logging messages (this would be where the gathering
options go). In my library this convenience was the
toast::log::log_stream which provides the operator<< similar to one of
your gatherers, but it is chosen to be used at the level of the client
logging messages, as opposed to being an enforced interface at the
application level. A consequence of this suggestion is that you must
standardize on logging levels as well (which means you should add a
few more than you have, and probably a few more than I have), although
it's possible that the application configure the log to ignore them,
they must exist in a predefined manner for the interface to remain
standard.

I think that is the biggest fundamental difference between our
libraries, so if you added that I may be very happy with it (at that
point I'll actually try out some code).

As a general comment, I really don't like the idea of the macro's.
Especially as short as you recommend, which certainly can't go in any
headers, so they need to be repeated in every source file, which means
they'll never be repeated the same and no one will be using a
consistent interface. Of course longer macro's which could go into a
header eliminate the usefulness of them in this case. I think if the
message processing and gathering were made efficiently enough, and the
interface simple enough, the motivation for macro's would go away. Of
course not all the overhead can be removed without that surrounding
if, but a lot can, and then users can always surround the message with
an if in the case that a profiler tells them to.

I also wasn't completely comfortable with the method of overriding
library types. I think this method would make my suggested goal very
difficult to implement. I haven't thought of a suggestion for you
yet.

As a C++ expert, you should know better than to provide and implicit
conversion to bool ;)

I just happened to notice, always_disabled is currently always
enabled.

Neal
 
J

jtorjo2007

Hi Neal,

First, thanks for the feedback!
It may go without saying that I like my logging libraries policy
based! In 2005 I wrote the toast logging library (released open
source last month, seehttp://toast.sourceforge.net/group__loggroup.html),

I will definitely take a look ;)
Since your process_msg_type determines the interface of how to
log, no library would be able to rely on there being a unified
interface. This is the motivation for the toast::log::log_handle

That is ok - the way you log (the Usage Syntax) is really up to you -
I don't want to enforce that on the users of the lib.
As a matter of fact, the previous version of the lib (which was
rejected) - had a unified interface - and that was considered bad by
the boost community ;)
class. Unfortunately this requirement makes your concept of gathering
(which I like) more difficult to implement. Obviously there is a run
time penalty for the type erasure, but it is a much smaller penalty
than having to recompile all your libraries whenever you change your
concrete logger, and there is no penalty at all for the application

I know ;) I haven't addressed compilation times yet - it's on my TODO
list :)
directly. I could have also done this with a base class and virtual
functions, but I didn't want to require the use of pointers and
virtual functions.

Not sure how I'll implement it, but I'll figure out a way (the older
version had something similar to what you suggest).
So ultimately what I would propose as a change for your library is to
have a basic interface, that can be relied upon to always remain the
same, which you can build facades on top of for the convenience of the
clients actually logging messages (this would be where the gathering

I want to go a bit further with this - as suggested by the boost
community: scenario templates. Since the lib is so flexible, it can
fit a lot of scenarios.
I will show how you can use the lib in different scenarios, and even
build macros for that (even though you hate them :))

options go). In my library this convenience was the
toast::log::log_stream which provides the operator<< similar to one of
your gatherers, but it is chosen to be used at the level of the client
logging messages, as opposed to being an enforced interface at the

That sounds time consuming. In my lib, the point of using gatherers is
that you can choose to implement your own more efficient way of
gathering the message (like, who knows, a better stringstream, a
cached string, using TLS, who knows).
I provide a few implementations, but if yuo can do better, or better
for a specific app, who am I to stop you from doing that?

As a side-note, another request (from Gennadiy Rozental) was to be
able to use the lib even if you don't want to use streams at all (as
lightweight as possible) - in my case, this is possible.
application level. A consequence of this suggestion is that you must
standardize on logging levels as well (which means you should add a

I don't like that - what if you don't want to use levels? It should be
your option, not enforced by the lib.
few more than you have, and probably a few more than I have), although

Adding logging levels is just too easy ;) They're just integers - they
each have a constant value. If you want to add levels in between, not
a problem :)
As a general comment, I really don't like the idea of the macro's.
Especially as short as you recommend, which certainly can't go in any
headers, so they need to be repeated in every source file, which means

I'm not particularly fond of macros myself - but I believe logging is
definitely one of those scenarios where you really need them.
Otherwise, how do you suggest implementing efficient logging? That is,
writing to a log, only if it's enabled.

Also, macros can go in headers - why not?
In my apps, I usually have a header called log.h or app_log.h, where I
define the logs of the application, and any other macros I might need.
That's a perfect place to define your application' macros.
I think if the
message processing and gathering were made efficiently enough, and the
interface simple enough, the motivation for macro's would go away. Of

I don't quite share this... Even if you can always say something like:

if ( g_l) g_l->str() << "repeating this " << "can be cumbersome";

....it'll still be cumbersome on the users of your log.


But in fact - using macros is up to you, so if you're happy with
writing like shown above, who am I to force you into using macros?
course not all the overhead can be removed without that surrounding
if, but a lot can, and then users can always surround the message with
an if in the case that a profiler tells them to.

Not sure I understand...
I also wasn't completely comfortable with the method of overriding
library types. I think this method would make my suggested goal very
difficult to implement. I haven't thought of a suggestion for you
yet.
Why?


As a C++ expert, you should know better than to provide and implicit
conversion to bool ;)

Why not? If you plan on not using macros, it's a blessing :)
I just happened to notice, always_disabled is currently always
enabled.

Ouch :) Thanks for pointing it out - fixed it, and will post a patch
soon.

Best,
John
 
R

Roland Pibinger

It may go without saying that I like my logging libraries policy
based! In 2005 I wrote the toast logging library (released open
source last month, see http://toast.sourceforge.net/group__loggroup.html),
which actually shares a lot of similarities to what you've got.

IMO, the age of 'boosted' libraries is gone. A library may be
configurable in some way as long as it provides reasonable defaults
('convention over configuration'). But configuration via policy
template parameters introduces high, unnecessary complexity that
hardly any real-world user is willing to accept.


--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
B

B.C.

IMO, the age of 'boosted' libraries is gone. A library may be
configurable in some way as long as it provides reasonable defaults
('convention over configuration'). But configuration via policy
template parameters introduces high, unnecessary complexity that
hardly any real-world user is willing to accept.

I don't know if the age of 'boosted' libraries is gone, but I ditto the fact
that 'configuration via policy template parameters introduces high,
unnecessary complexity'. At least for the two logging libraries, torjo and
toast.

I checked the examples in both and I must say my brain went a bit numb.

OK, let me explain myself. I do programming in Java part time and I use
log4j to do the logging, and I was looking for a similar library but for
C++. My first choice was log4cpp but then I read your message. I am pretty
sure you did your homework and you took a look at log4j even if it is not a
c++ library - there is much to learn from Java in the C++ world! It uses the
concept of specialized loggers - you can log to files, to databases, to
tcp/ip sockets, you can send emails etc (I guess a specialized logger maps
to your concept of policy). One of the greatest things about log4j is that
you can configure the logging on the fly, at runtime, by changing the log4j
configuration file, without having to change and recompile your application.
You can assign names to loggers, and usually the names are complete class
names including the package name. So, when I need logging in a class all I
do is declare:

class MyClass {
private static final Logger log = Logger.getLogger(MyClass.class);

public void myfunction()
{
log.debug("....");
// or
log.error("...")
// and so on
}
}

If I want a specialized Logger for my class then I have to map it to a
specialized logger in the configuration file. Log4j will do the rest.
Otherwise Log4j will use a default logger.

Using your libraries:
- Can you change the logging levels at runtime without having to recompile
the application?
- Can you switch the logging levels only for specific classes, also at
runtime without having to recompile the application?
- the ultimate question, are your libraries at least as simple to use as
log4j even if we are talking about c++?

And now, some concrete critique:
On this page,http://torjo.com/log2/index.html, the examples. Please note the
titles:

Example 1: you choose to use the L_(msg) sytax:
Example 2: you choose to use the L_ << "some " << " cool " << "log message"
syntax
Example 3: you choose to use the same syntax as Example 2, but also use
formatters and destinations.
Example 4: you choose to use levels

Your examples are driven by different syntaxes that can be employed to do
the same thing which is what exactly?!

Your examples should show me how to use your library in the easiest and
simplest manner to solve some logging problems that you think might occur in
the real world. They don't have to be the most complicated examples, but you
know, they should give me the taste of your library.

IMO your examples should be something like this:

Example 1: How to log to a file - here you can create 2, 3 classes that call
each other and put some logging statements.
Example 2: How to add logging to a file to an existing application - this is
probably one of the most common patterns of usage of your library.
Example 3. How to log in two different files. Here you have: class A logs to
file1, class B logs to file1 and file2, class C logs only to file 3
Example 4: How to log to syslog or to the event log (on windouz) - same
thing
Example 5: How to log in a multithreaded application. Here you just do a
simple application that starts and stops two threads that log messages
Example 6: How to use a configuration file to configure the logging.

And so on. The bottom line is: if I evaluate your library, I want to see how
I can use your library to perform simple, concrete tasks that your library
is supposed to help me with. I want to see the 5000ft view of your library -
which is what I can and can't do with it, then I want to "sample" it with
simple examples that try to solve some sketchy real world requirements.

After I checked your examples, and having the experience with log4j, I just
can't go any further exploring and testing your libary. It is too
complicated for my taste and I don't want to spend any more time to dig into
it. I would rather build my own Logger class that simply logs to a file.

May I make the suggestion that it would probably be better to have the
examples as full compilable applications that can be downloaded.

The examples in the Toast library are slightly better, but still bare bones,
and they raise questions rather than showing what you can actually do. I
didn't try log4cpp, but I was surely surprised when it was mentioned on one
of your pages that it was not fast enough. Well, I believe you. I didn't
have any performance problem with log4j (I assume log4j is slower than
log4cpp), but my requirements for speed were not as severe as in your case.

I know you all have time constraints - it is free software in the end - but
if you spend more time to present it in a friendlier way to your users (that
in the best scenario otherwise changes in the library might be required), I
think more and more people would feel compelled to use the boost logging
library.

B.C.
 
J

jtorjo2007

Hi Roland,
IMO, the age of 'boosted' libraries is gone. A library may be

This seems quite biased.
configurable in some way as long as it provides reasonable defaults

Well, that's the plan - to provide reasonable defaults.
('convention over configuration'). But configuration via policy
template parameters introduces high, unnecessary complexity that
hardly any real-world user is willing to accept.

It all depends on ease of use. I will definitely provide defaults and
easy configuration for different scenarios.

Best,
John


--
http://John.Torjo.com -- C++ expert
.... call me only if you want things done right


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
D

David Abrahams

IMO, the age of 'boosted' libraries is gone. A library may be
configurable in some way as long as it provides reasonable defaults
('convention over configuration'). But configuration via policy
template parameters introduces high, unnecessary complexity that
hardly any real-world user is willing to accept.

I object to this false association between Boost libraries and
policy-based designs. PBD certainly has its place and value, but
Boost has historically in many cases been resistant to the adoption of
policy-based designs, and has often focused instead on designs that
favor type-erasure, most notably in boost::shared_ptr. These designs
avoid that complexity and preserve interface compatibility.

You need to look elsewhere to place the credit or blame for the
popularity of PBD.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
R

Roland Pibinger

Using your libraries:
- Can you change the logging levels at runtime without having to recompile
the application?

Should be no problem for any logging library.
- Can you switch the logging levels only for specific classes, also at
runtime without having to recompile the application?
- the ultimate question, are your libraries at least as simple to use as
log4j even if we are talking about c++?

Java is a much more dynamic language than C++. Everything (almost) is
an Object and be accessed by reflection. You cannot assume the same
flexibility from C++. But you can at least ask for a library that
shields the configuration options from the user interface.


--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
R

Roland Pibinger

Well, that's the plan - to provide reasonable defaults.


It all depends on ease of use. I will definitely provide defaults and
easy configuration for different scenarios.

The problem with policy template parameters is that they are an
unavoidable part of the user interface and e.g. pop up in compiler
error messages.


--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
J

jtorjo2007

I don't know if the age of 'boosted' libraries is gone, but I ditto the fact
that 'configuration via policy template parameters introduces high,
unnecessary complexity'. [...]
I checked the examples in both and I must say my brain went a bit numb.

It just needs a bit of getting used to - just like anything new ;)
[..] there is much to learn from Java in the C++ world! It uses the
concept of specialized loggers - you can log to files, to databases, to
tcp/ip sockets, you can send emails etc (I guess a specialized logger maps

Yes, this is available with my lib as well - the concept of
"destinations".
to your concept of policy). One of the greatest things about log4j is that
you can configure the logging on the fly, at runtime, by changing the log4j
configuration file, without having to change and recompile your application.

In fact if you wish, you can add that on top of my logging lib -
perhaps I'll do it later, if I have the time.
You can assign names to loggers, and usually the names are complete class
names including the package name. So, when I need logging in a class all I
do is declare:

class MyClass {
private static final Logger log = Logger.getLogger(MyClass.class);

public void myfunction()
{
log.debug("....");
// or
log.error("...")
// and so on
}

This is sooo twisted ;) Why declare a logger in each of your class,
when you can use a global one?
Anyway, it's your program, you can do as you wish :)
Using your libraries:
- Can you change the logging levels at runtime without having to recompile
the application?

What do you mean by that?
- Can you switch the logging levels only for specific classes, also at
runtime without having to recompile the application?

I really don't know why you'd want that kind of granularity (class
level), but I guess you could do it.
- the ultimate question, are your libraries at least as simple to use as
log4j even if we are talking about c++?

Well I know the docs need a bit of work ,and I'm working on that -
basically, I want to provide you with scenarios - and how you should
use the lib in each scenario.
And now, some concrete critique:
On this page,http://torjo.com/log2/index.html, the examples. Please note the
titles:

Example 1: you choose to use the L_(msg) sytax:
Example 2: you choose to use the L_ << "some " << " cool " << "log message"
syntax
Example 3: you choose to use the same syntax as Example 2, but also use
formatters and destinations.
Example 4: you choose to use levels

Your examples are driven by different syntaxes that can be employed to do
the same thing which is what exactly?!

They all do logging - it's just that the usage syntax can be
different. And that is for you to decide - do you want to trade speed
for ease of use (in our case : speed : Example 1, ease of use :
Example 2)
Your examples should show me how to use your library in the easiest and
simplest manner to solve some logging problems that you think might occur in
the real world. They don't have to be the most complicated examples, but you
know, they should give me the taste of your library.

IMO your examples should be something like this:

Example 1: How to log to a file - here you can create 2, 3 classes that call
each other and put some logging statements.

See test_simple_dump_to_cout.cpp - it simply dumps to cout.
See test_multiple_simple_logs.cpp - one log dumps to cout, one to
file, one to debug window
Example 2: How to add logging to a file to an existing application - this is
probably one of the most common patterns of usage of your library.
Example 3. How to log in two different files. Here you have: class A logs to
file1, class B logs to file1 and file2, class C logs only to file 3
Example 4: How to log to syslog or to the event log (on windouz) - same
thing

I will write about this - but basically examples 2., 3., 4. - you can
implement them in so many ways.
One way is to use formatters and destinations - as defined by my
logging lib.
But in case you find a faster way, you can simply use that (see the
Workflow of processing a message)

And so on. The bottom line is: if I evaluate your library, I want to see how
I can use your library to perform simple, concrete tasks that your library
is supposed to help me with. I want to see the 5000ft view of your library -
which is what I can and can't do with it, then I want to "sample" it with
simple examples that try to solve some sketchy real world requirements.

You're right. As said, there's more docs to be added - what you want
is definitely in my TODO list.
May I make the suggestion that it would probably be better to have the
examples as full compilable applications that can be downloaded.

There are fully compilable examples - see the 'tests' directory.
I know you all have time constraints - it is free software in the end - but
if you spend more time to present it in a friendlier way to your users (that
in the best scenario otherwise changes in the library might be required), I
think more and more people would feel compelled to use the boost logging
library.

Again, I'll do that - thanks for the feedback ;)

Best,
John


--
http://John.Torjo.com -- C++ expert
.... call me only if you want things done right


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
J

jtorjo2007

It all depends on ease of use. I will definitely provide defaults and
The problem with policy template parameters is that they are an
unavoidable part of the user interface and e.g. pop up in compiler
error messages.

Then all I have to do is make sure there won't be any compile
errors :p
That is, initializing the lib will be just a few lines of code.

Best,
John


--
http://John.Torjo.com -- C++ expert
.... call me only if you want things done right


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
N

Neal E. Coombes

FWIW, I made a toy logging library, which applies "type erasure" to
streams.
If interested, see:http://p-stade.sourceforge.net/napkin/index.html

It's cute. I like most of it. It wouldn't likely meet our
performance requirements but is dead simple. The only thing I would
change is the PSTADE_IF_DEBUG and PSTADE_UNPARENTHESIZE which are
completely unnecessary. At least the unparenthesize one is. You
could define PSTADE_IF_DEBUG as 'if(true)' and 'if(false)' and then
require the user uses {} instead of (), or you could just have the
user type 'if(PSTADE_DEBUG)' themselves. Either way just about every
compiler I know of will completely remove the if when the conditional
is a constant literal.

Neal
 
N

Neal E. Coombes

The problem with policy template parameters is that they are an
unavoidable part of the user interface and e.g. pop up in compiler
error messages.

I agree, but care can be taken to make the error messages at least
readable. I use the boost concept checking library to ensure that the
template parameters passed in meet the requirements, this should
produce much shorter and more immediate error messages when something
is wrong with a policy. It will be improved even more with C++0x with
concepts being built right into the language.

Neal
 
N

Neal E. Coombes

I don't know if the age of 'boosted' libraries is gone, but I ditto the fact
that 'configuration via policy template parameters introduces high,
unnecessary complexity'. At least for the two logging libraries, torjo and
toast.

I think that policy based design is something that most programmers
are unfortunately not familiar with. I don't think it's hard to
understand though. It just takes that initial effort. And it's not
that much, I mean imagine C programmers learning OOP, that's -real-
effort, nothing like that kind of effort is required to understand
PBD. And once you do, I think that the interface to toast::logger is
actually very simple considering the power it gives the user.
Completely configurable at compile time for ultimate performance and
flexibility. I can give you the same amount of flexibility the old
fashioned way and no one would complain about the complexity (even
though it's almost exactly the same amount, just implemented
traditionally through runtime dispatching instead of compile time
dispatching). Unfortunately that traditional method is too slow for
some of our apps, and instead their authors resorted to hand coding
tight logging. My library was the direct result of not wanting
inconsistent hand coded interfaces all over the place in my companies
code.
Using your libraries:
- Can you change the logging levels at runtime without having to recompile
the application?
- Can you switch the logging levels only for specific classes, also at
runtime without having to recompile the application?
- the ultimate question, are your libraries at least as simple to use as
log4j even if we are talking about c++?

The problem with toast::log is that you can do anything you want.
Thus it's impossible to document all the possibilities. The answer to
your first two questions is yes. I've personally never used log4j, or
log4cpp, but so far the only feedback I've received (after the first
step of understanding PBD) is that it's remarkably simple to use.
The examples in the Toast library are slightly better, but still bare bones,
and they raise questions rather than showing what you can actually do. I
didn't try log4cpp, but I was surely surprised when it was mentioned on one
of your pages that it was not fast enough. Well, I believe you. I didn't
have any performance problem with log4j (I assume log4j is slower than
log4cpp), but my requirements for speed were not as severe as in your case.

I would greatly appreciate it if you asked me the questions raised ;)
I'd be happy to write more examples. If your performance requirements
aren't high, you may very well be happy with log4cpp. I hope though
that any logger that makes it into boost serves all markets and not
just the ones where performance isn't a concern.

Neal
 
N

Neal E. Coombes

That is ok - the way you log (the Usage Syntax) is really up to you -
I don't want to enforce that on the users of the lib.
As a matter of fact, the previous version of the lib (which was
rejected) - had a unified interface - and that was considered bad by
the boost community ;)

I think I probably explained my one point too much in my previous
message :) The whole point of my message really was simply to ask for
any boost::logger to provide a feature that allows me to pass in any
logger type to a library at runtime, without that library knowing the -
exact templatized type- of the logger when it was compiled.

Just about everything in my message other than this feature request
was simply my description of what I think are natural consequences of
providing this feature. If you can get around them somehow, that's
great. But I think that in order to provide this feature you must
provide a basic interface that will never change. That's not to say
that it can't be customized for the applications direct use, but there
must be a basic interface there somewhere.
I know ;) I haven't addressed compilation times yet - it's on my TODO
list :)

It's not the compilation time that matters, it's the fact that I as a
library writer may not have given you the source code to recompile at
all. And yet it would still be useful for me to provide an interface
that will accept some boost::logger for me to log to it.
I don't like that - what if you don't want to use levels? It should be
your option, not enforced by the lib.

Again I think this is a natural consequence of being able to pass -
some logger- into a library. You don't require that the application
pay attention to these levels, or even that the levels are mandatory
for logging a message in the basic interface, simply that they exist
for the library to use should they choose. There is a fundamental
disconnect between the application and the library, there is simply no
way to at application compile time tell the library the details about
the logger type, some minimal details need to be known ahead of time.
I'm not particularly fond of macros myself - but I believe logging is
definitely one of those scenarios where you really need them.
Otherwise, how do you suggest implementing efficient logging? That is,
writing to a log, only if it's enabled.

In the toast::logger, I provide two functions, message and
forced_message. message is safe and does the check on your behalf,
forced_message logs regardless leaving you responsible for doing the
check. I think that efficient logging is very important, it's one of
the primary motivations for my having written the toast::logger, but
it's only important sometimes. The most convenient interface possible
is the most important the rest of the time.
Also, macros can go in headers - why not?
In my apps, I usually have a header called log.h or app_log.h, where I
define the logs of the application, and any other macros I might need.
That's a perfect place to define your application' macros.

The point I was trying to make is that there can be no convenient
standard macros, every client of your library uses their own hand
crafted macro, so there is no consistency.
I don't quite share this... Even if you can always say something like:

if ( g_l) g_l->str() << "repeating this " << "can be cumbersome";

...it'll still be cumbersome on the users of your log.

But in fact - using macros is up to you, so if you're happy with
writing like shown above, who am I to force you into using macros?

why make me use macros to have a convenient syntax?? Why not:

log << INFO << "this is a " << "convenient syntax";

This can be made reasonably efficient, although it does increase the
checks from one to one for every <<.
Not sure I understand...

If the convenient syntax I mentioned just above is in your critical
path (i.e. your profiler tells you logging is slowing you down), then
I can surround it with an if:

if(log.check(INFO)) // confirm that info messages will be logged:
log << INFO << "good old " << "convenient syntax";

I would only do this if necessary for performance. And if it was
necessary a LOT, then I might consider writing a macro. I think that
recommending macros from the start though is not a great idea, and I
think that you should provide the convenient interface without the
macros.

Well I don't like the dependence on order. It also seems like you
can't have loggers of different char types in the same unit for
example. I'm not sure how you would reconcile this with the feature
I'm requesting to be able to pass a logger to libraries. I still
haven't had time to think of all the reasons I don't like it, or of a
suggestion for how to replace it though :)
Why not? If you plan on not using macros, it's a blessing :)

implicit conversion to bool can cause all sorts of unexpected
conversions. Better to use an 'unspecified-bool-type' like a pointer
to member function.

struct A
{
typedef (void A::*unspecified_bool_type)(bool);

bool enabled;
void set(bool b) { enabled = b }

operator unspecified_bool_type()
{
return enabled ? &A::set : 0;
}
};

This will convert in all the right places (like in the condition to an
if).
 
A

Alex

OK, let me explain myself. I do programming in Java part time and I use
log4j to do the logging, and I was looking for a similar library but for
C++. My first choice was log4cpp but then I read your message. I am pretty
sure you did your homework and you took a look at log4j even if it is not a
c++ library - there is much to learn from Java in the C++ world! It uses the
concept of specialized loggers - you can log to files, to databases, to
tcp/ip sockets, you can send emails etc (I guess a specialized logger maps
to your concept of policy). One of the greatest things about log4j is that
you can configure the logging on the fly, at runtime, by changing the log4j
configuration file, without having to change and recompile your application.
You can assign names to loggers, and usually the names are complete class
names including the package name.

You may want to check out POCO Logging package (part of the Foundation
library)

http://pocoproject.org

Alex
 
S

shunsuke

It's cute. I like most of it. It wouldn't likely meet our
performance requirements but is dead simple. The only thing I would
change is the PSTADE_IF_DEBUG and PSTADE_UNPARENTHESIZE which are
completely unnecessary. At least the unparenthesize one is. You
could define PSTADE_IF_DEBUG as 'if(true)' and 'if(false)' and then
require the user uses {} instead of (), or you could just have the
user type 'if(PSTADE_DEBUG)' themselves.

An if-statememnt introduces a scope.
Anyway I tend to prefer #if to IF_DEBUG these days.
Either way just about every
compiler I know of will completely remove the if when the conditional
is a constant literal.

Thanks for the good news. I didn't know certainly that. :)
I will update my debugging macros, which will be something like:

DEBUG_EXPR(std::cout) << 1 << 2 << 3;
DEBUG_BLOCK { std::cout << 1 << 2 << 3; }


Regards,
 
J

jtorjo2007

I don't know if the age of 'boosted' libraries is gone, but I ditto the fact
that 'configuration via policy template parameters introduces high,
unnecessary complexity'. At least for the two logging libraries, torjo and
toast.

I checked the examples in both and I must say my brain went a bit numb.
Is this simple enough? ;)
(knowing what it actually does for you)

http://svn.boost.org/svn/boost/sand...g/samples/scenarios/mul_levels_one_logger.cpp

(basically I'm making the lib easier to use - more examples coming
soon :) )

Best,
John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top