
1) A given message is directed to a particular named log, from where it is sent to 1 or more named appenders. It is easy to connect/disconnect appenders to logs. It is also easy to set the log level. However, I find the log level facility useless, because in general I want to filter the messages to a particular appender, not globally - if one of my appenders is the system error log, I always want errors, all errors, and nothing else, going to it. If I have some sort of console debug output, I might want to turn on debug level output to it alone (in general from only a few logs). I can do this reasonably well if I connect the "system error log" to "*.error" and adjust what goes to the "debug console" by specifying eg. "foo.bar.debug" output to go there, or more likely "foo.bar.*" and turning off "foo.bar.debug" if it is too noisy. If some library author decides that log levels are the way to go, I can't get my app to direct that libraries errors to the error log. Alternatively, if I write a library, and I want to ensure that it is useable in this scenario and in some level-based logging scheme, I would presumably need to log an error with a level of err to a log called "mylib.error" and require that the app using mylib connect appenders to "mylib.*" and set levels on "mylib.*" if the app is
I see what you mean. I believe that Gennady's solution of filtering is the way to go. It is very powerful - it took me a while to get it, but now I understand ;)
Extending logger_and_bool to logger_and_predicate and the appropriate c'tors for the keeper/enabled_log would allow the predicate to perform checks that require access to the logger itself as well. These tests are (potentially) heavyweight but so long as a simple call to BOOST_LOG simply bypasses them there is no cost to the user who doesn't need them.
Yup, you're right.
2) While the library aims to offer a customisation point through replacing the manager type, the manager concept is un(der)documented, and the various interfaces that depend on the manager type are too closely coupled to allow much customisation anyway. Note that this may be ok, if the design of the standard manager is flexible enough without extensive customisation, and any remaining customisation points/concepts are clearly documented. In any case, the use of the customisation needs to be illustrated by example (ie. an alternate manager replacing all the default interfaces).
Yes, I definitely need more docs.
3) Closely related to the above, I would like to see cleaner separation between the components that make up this library. This is something that is hard to do when the implementation is a feature driven moving target (I've been trying to do it on and off). This separation needs to maintain or increase the existing loose coupling between compilation units that use the library to log, those that set/modify filtering and those that do actual output of logged messages, while reflecting that separation in the implementation. Currrently appenders do this, but the logging and filtering is too internally intertwined. If the library formalised that separation allowing each module to be customised, library code could use logging independent of how the application (or other libraries) used it/controlled it (and without forcing library recompilation).
Yes, as I will redesign it, this will definitely happen.
5) While applying modifiers to logs rather than to appenders is (potentially) more efficient as it avoids doing the modification N times for N appenders, in reality I have yet to encounter a case where the log format wasn't associated with the destination, rather than the source (ie. a log file should have a consistent format). An extreme example is when the log is a structured log such as the windows event log. A simple example is the newline modifier. If an appender is expecting to receive log messages it is up to the appender to delimit the messages in the appropriate way - be that by packing it into a syslog UDP packet or just sticking a newline on the end. I don't think the newline modifier should exist at all, but in other cases it does make sense to include log specific information. I'm not sure that for typical use where N is small that the efficency gains are likely to be significant, but it would also be possible to improve efficiency issue in cases where it is a real concern by using a multiplexing appender (that forwarded formatted output multiple "real" appenders).
I still like the modifier concept, but I do see your point. In the future, I'd like to provide modifiers, which I think are useful impelmented alone (like: newline, prepend_time, etc.), BUT, have the appenders call them, if needed.
The modifier concept also blurs the line between insertion of information and formatting - if a log should always contain some particular information at the start of it what is wrong with just writing it to the enabled_logger's stream when it is created. This also leverages all the built-in and extended output and formatting facilities of std streams (including rather more internationalisation support than found in strings). This fits in with the user extensible logger attributes, predicates etc above. I would like to see 2 points at which the content can be modified - when the stream is created, so that informartion that should be a prefix on all logged messages via a particular log, regardless of destination can be inserted there, and another associated with the appender, rather than any particular log, so that any content that must always be inserted in messages to that log can be inserted/formatted there.
Yes, when I'll redesign the lib, I'll make it possible to format the string at any time. Thanks for the review. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/surfaces.html - Sky's the limit! -- http://www.torjo.com/cb/ - Click, Build, Run!