
Dear boosters, Finally, found some time to work on the logging library ;) (for those interested - find it at http://groups.yahoo.com/group/boost/files/logging.zip or http://www.torjo.com/code/logging.zip) note: this first draft works only for Win32 :( In short, it makes it very easy to log messages, while being efficient. And on top of that, it's thread-safe. Table of contents: ****** Declaring/defining logs ****** Log hierarchies ****** Modifier/ Log functions ****** Enabling/disabling of logs ****** Example ****** Declaring/defining logs Every log has: - a unique ID, by which you refer when you write to it - a name, by which you can modify its behavior (for example, enabling/disabling). The name is very useful so that you can manipulate multiple logs at once (for instance, disable multiple logs at once) and to be externally known - to easily manipulate logs at run-time. Also, this way is also easier to form hierarchies of logs (see below). Cutting to the chanse: // declare a log, in a header file BOOST_DECLARE_LOG(dbg) // define the log, in a source file BOOST_DEFINE_LOG(dbg, "app.dbg") // writing to the log BOOST_LOG(dbg) << "this is a debug message, i=" << i << std::endl; ****** Log hierarchies Logs can be hierarchical. In a hierarchy, a log inherits all anscestors' behaviors. Log A is said to be a descendant of Log B if when B's name starts with A's name (example: "app.charts.gui.dbg" is a descendant of "app.charts", but not a descendant of "app.err") When manipulating logs, you're always manipulating a hierarchy - the wildcard '*' stands for "anything" - see below. ****** Modifier/ Log functions When a message is written to a log, the following will happen: - first, check if the log is enabled. If so, continue. Otherwise, do nothing. - run all modifiers for this message - run all log functions for this message A modifier is a function that can modify the original message before it's printed to any destination. Examples can be: prefix the message with the current time, or prefix the message with the current thread ID. The log function is a function that will actually print this message to a destination. An example: void write_to_cout(const std::string &, const std::string &msg) { std::cout << msg; } When setting modifier/log functions, you're manipulating hierarchies of logs. Example: // add this modifier to all logs that start with "app" name add_modifier_func("app*", &write_prefix); // write all messages to cout add_log_func("*", write_to_cout); ****** Enabling/disabling of logs By default, all logs are enabled. You can specifically enable/disable some of them - wildcards work. Example: // disable all logs disable_logs("*"); // enable all dbg logs enable_logs("*dbg*"); Note that enabling/disabling is VERY EFFICIENT. In case a log is not enabled, the code after BOOST_LOG(...) is not executed AT ALL. Example: BOOST_LOG(app) << some_time_consuming_msg << std::endl; If 'app' is disabled, some_time_consuming_msg will not be executed. ****** Example // full sample found in logging.zip // Modifiers for all: // [type_of_message] original_message append_enter_if_needed add_modifier_func("*", &prefix_time, std::numeric_limits<int>::max() ); add_modifier_func("*", &append_enter); // Modifiers for app and its ascendants // <time> [type_of_message] original_message append_enter_if_needed add_modifier_func("app*", &write_prefix); // Modifiers for "app" only // <time> [Thread ID] [type_of_message] original_message append_enter_if_needed add_modifier_func("app", &prepend_thread_id, 0); // Log Functions // all messages are written to cout add_log_func("*", write_to_cout); // "app*" messages are written to file as well add_log_func("app*", write_to_file); // 'app' only and dbg messages are written to Output Debug Window as well add_log_func("app", write_to_dbg_wnd); add_log_func("*dbg*", write_to_dbg_wnd); int i = 1, j = 2, k = 3; BOOST_LOG(app) << "testing" << i << '-' << j << '-' << k; // written to both cout & the file & Output Debug Window BOOST_LOG(dbg) << "this is a debug message, i=" << i << std::endl; BOOST_LOG(info) << "I just wanted to tell you something...."; BOOST_LOG(warn) << "Logged-on Users approach max. limit"; BOOST_LOG(err) << "Too many users!"; BOOST_LOG(charts::gui) << "Creating main window" << std::endl; BOOST_LOG(charts::dbg) << "A debug msg coming from {charts} module" ; BOOST_LOG(charts::gui) << "Destroying main window" << std::endl; // disable all descendants of 'app' (not the 'app' itself) disable_logs("app.*"); BOOST_LOG(dbg) << "this won't be written" << std::endl; BOOST_LOG(app) << "However, this msg. will" << std::endl; enable_logs("app.dbg"); // specifically, only dbg log is enabled back now BOOST_LOG(dbg) << "this will be written - this log just got enabled" << std::endl; BOOST_LOG(err) << "this still won't be written" << std::endl; enable_logs("app.*"); disable_logs("app.dbg"); // now, all logs are back to the 'enabled' state BOOST_LOG(err) << "this will be written - all logs are enabled" << std::endl; // disable all logs disable_logs("*"); BOOST_LOG(err) << "this won't be written" << std::endl; BOOST_LOG(app) << "neither will this" << std::endl; BOOST_LOG(dbg) << "or this..." << std::endl; BOOST_LOG(warn) << "or this..." << std::endl; BOOST_LOG(info) << "or this..." << std::endl; // enable all dbg logs enable_logs("*dbg*"); BOOST_LOG(app) << "this won't be written" << std::endl; BOOST_LOG(dbg) << "this will be written" << std::endl; BOOST_LOG(info) << "this won't be written" << std::endl; // enable info log enable_logs("*info*"); BOOST_LOG(info) << "a simple info" << std::endl; /*** Console 18:59:44 [app] [Thread 1384] testing1-2-3 18:59:44 [app.dbg] this is a debug message, i=1 18:59:44 I just wanted to tell you something.... 18:59:44 [app.warn] Logged-on Users approach max. limit 18:59:44 [app.err] Too many users! 18:59:44 Creating main window 18:59:44 A debug msg coming from {charts} module 18:59:44 Destroying main window 18:59:44 [app] [Thread 1384] However, this msg. will 18:59:44 [app.dbg] this will be written - this log just got enabled 18:59:44 [app.err] this will be written - all logs are enabled 18:59:44 [app.dbg] this will be written 18:59:44 a simple info */ /*** Output Debug Window 19:00:03 [app] [Thread 1384] testing1-2-3 19:00:03 [app.dbg] this is a debug message, i=1 19:00:03 A debug msg coming from {charts} module 19:00:03 [app] [Thread 1384] However, this msg. will 19:00:03 [app.dbg] this will be written - this log just got enabled 19:00:03 [app.dbg] this will be written */ /*** out.txt file 19:00:03 [app] [Thread 1384] testing1-2-3 19:00:03 [app.dbg] this is a debug message, i=1 19:00:03 [app.warn] Logged-on Users approach max. limit 19:00:03 [app.err] Too many users! 19:00:03 [app] [Thread 1384] However, this msg. will 19:00:03 [app.dbg] this will be written - this log just got enabled 19:00:03 [app.err] this will be written - all logs are enabled 19:00:03 [app.dbg] this will be written */ There's some more work - the docs also ;) , but I'm pretty happy with the first draft. What do you all think? Best, John -- John Torjo Freelancer -- john@torjo.com -- http://www.torjo.com/logview/ - viewing/filtering logs is just too easy!

I'm very interested in a good (simple) logging library. I haven't looked at your code yet, but you say win32 only. Do you know what is needed to port to posix/gcc3 platforms? Is the effort large?

Neal D. Becker wrote:
I'm very interested in a good (simple) logging library. I haven't looked at
it is simple indeed. Just think that the whole code resides now in only 3 files!
your code yet, but you say win32 only. Do you know what is needed to port to posix/gcc3 platforms? Is the effort large?
No, the effort is not large. What I'll need to do is port the TSS part - any help is deeply appreciated -, and use boost.thread for locking - quite little. Best, John -- John Torjo Freelancer -- john@torjo.com -- http://www.torjo.com/logview/ - viewing/filtering logs is just too easy!

John Torjo wrote:
Neal D. Becker wrote:
I'm very interested in a good (simple) logging library. I haven't looked at
it is simple indeed. Just think that the whole code resides now in only 3 files!
your code yet, but you say win32 only. Do you know what is needed to port to posix/gcc3 platforms? Is the effort large?
No, the effort is not large. What I'll need to do is port the TSS part -
Are you using Boost.Threads tss? Many of its limitations have been addressed in the upcoming Boost release, though unfortunately the cleanup issue in statically linked Win32 builds hasn't been dealt with, yet.
any help is deeply appreciated -, and use boost.thread for locking - quite little.
Mike

Michael Glassford wrote:
John Torjo wrote:
Neal D. Becker wrote:
I'm very interested in a good (simple) logging library. I haven't looked at
it is simple indeed. Just think that the whole code resides now in only 3 files!
your code yet, but you say win32 only. Do you know what is needed to port to posix/gcc3 platforms? Is the effort large?
No, the effort is not large. What I'll need to do is port the TSS part -
Are you using Boost.Threads tss? Many of its limitations have been addressed in the upcoming Boost release, though unfortunately the cleanup issue in statically linked Win32 builds hasn't been dealt with, yet.
nope. not using Boost.Threads tss yet. As I said, I've implemented it Win32 only yet - so I'm using TlsAlloc/TlsSlot/etc. Do you recommend I get the latest boost.thread? By the way, does the latest Boost.Thread allow for static linking? If not, I won't use it yet - it's really annoying (not having static linking). Best, John -- John Torjo Freelancer -- john@torjo.com -- http://www.torjo.com/logview/ - viewing/filtering logs is just too easy!

John Torjo wrote:
Michael Glassford wrote:
John Torjo wrote:
Neal D. Becker wrote:
I'm very interested in a good (simple) logging library. I haven't looked at
it is simple indeed. Just think that the whole code resides now in only 3 files!
your code yet, but you say win32 only. Do you know what is needed to port to posix/gcc3 platforms? Is the effort large?
No, the effort is not large. What I'll need to do is port the TSS part -
Are you using Boost.Threads tss? Many of its limitations have been addressed in the upcoming Boost release, though unfortunately the cleanup issue in statically linked Win32 builds hasn't been dealt with, yet.
nope. not using Boost.Threads tss yet. As I said, I've implemented it Win32 only yet - so I'm using TlsAlloc/TlsSlot/etc.
Do you recommend I get the latest boost.thread? By the way, does the latest Boost.Thread allow for static linking? If not, I won't use it yet - it's really annoying (not having static linking).
This will be in the release notes: Static-link build option added The option to link Boost.Threads as a static library has been added back with some limitations. This feature was originally removed because boost::thread_specific_ptr required that Boost.Threads be dynamically linked in order for its cleanup functionality to work on Win32 platforms. Several options are currently being explored to resolve this issue. In the meantime, the ability to link Boost.Threads statically has been added back with boost::thread_specific_ptr support removed from the statically linked version. The decision to add it back was made because its lack is one of the most frequent complaints about Boost.Threads and because the other approaches that are being investigated to deal with boost::thread_specific_ptr cleanup look fairly promising. Note Boost.Threads is still dynamically linked by default. In order to force it to be statically linked, it is necessary to #define BOOST_THREAD_USE_LIB before any of the Boost.Threads header files are #included. Note If the boost::thread_specific_ptr cleanup issue cannot be resolved by some other means, it is highly likely that the option to statically link Boost.Threads will be removed again in a future version of Boost, at least for Win32 platforms. This is because the boost::thread_specific_ptr functionality will be increasingly used by Boost.Threads itself, so that proper cleanup will become essential in future versions of Boost.Threads. Mike

[snip] Static-link build option added
The option to link Boost.Threads as a static library has been added back with some limitations. This feature was originally removed because boost::thread_specific_ptr required that Boost.Threads be dynamically linked in order for its cleanup functionality to work on Win32 platforms. Several options are currently being explored to resolve this issue. In the meantime, the ability to link Boost.Threads statically has been added back with boost::thread_specific_ptr support removed from the statically linked version. The decision to add it back was made because its lack is one of the most frequent complaints about Boost.Threads and because the other approaches that are being investigated to deal with boost::thread_specific_ptr cleanup look fairly promising.
so if I get the latest boost.thread I'll have all this (ability to use it as a static lib)?
Note Boost.Threads is still dynamically linked by default. In order to force it to be statically linked, it is necessary to #define BOOST_THREAD_USE_LIB before any of the Boost.Threads header files are #included.
I'm not sure this is ok with me. I think it should still be statically linked by default (see below).
Note If the boost::thread_specific_ptr cleanup issue cannot be resolved by some other means, it is highly likely that the option to statically link Boost.Threads will be removed again in a future version of Boost, at least for Win32 platforms. This is because the boost::thread_specific_ptr functionality will be increasingly used by Boost.Threads itself, so that proper cleanup will become essential in future versions of Boost.Threads.
Again, I don't understand why you need thread_specific_ptr within boost.threads so much. Anyway, if you need thread_specific_ptr so much, maybe we could do away with two libraries, something like: 'thread' and 'thread_ext' or so. In the thread, we should keep what was roughly before: - mutexes (don't tell me they need TLS) and scoped locks - thread class (no cleanup support) - xtime In the thread_ext, include whatever needs thread_specific_ptr, and extra goodies - this will have the statically/dynamically linked issue. I think this would be quite good in the long run, since there are so many libs/applications that only need basic thread support, and who really don't want an extra DLL added to the maintenance list. Best, John -- John Torjo Freelancer -- john@torjo.com -- http://www.torjo.com/logview/ - viewing/filtering logs is just too easy!

John Torjo wrote:
[snip] Static-link build option added
The option to link Boost.Threads as a static library has been added back with some limitations. This feature was originally removed because boost::thread_specific_ptr required that Boost.Threads be dynamically linked in order for its cleanup functionality to work on Win32 platforms. Several options are currently being explored to resolve this issue. In the meantime, the ability to link Boost.Threads statically has been added back with boost::thread_specific_ptr support removed from the statically linked version. The decision to add it back was made because its lack is one of the most frequent complaints about Boost.Threads and because the other approaches that are being investigated to deal with boost::thread_specific_ptr cleanup look fairly promising.
so if I get the latest boost.thread I'll have all this (ability to use it as a static lib)?
Yes, but without tss on Win32.
Note Boost.Threads is still dynamically linked by default. In order to force it to be statically linked, it is necessary to #define BOOST_THREAD_USE_LIB before any of the Boost.Threads header files are #included.
I'm not sure this is ok with me. I think it should still be statically linked by default (see below).
It would, perhaps, except that the static lib doesn't include tss on Win32. I hope it will in the release following the upcoming release, at which point the BOOST_THREAD_USE_LIB would disappear.
Note If the boost::thread_specific_ptr cleanup issue cannot be resolved by some other means, it is highly likely that the option to statically link Boost.Threads will be removed again in a future version of Boost, at least for Win32 platforms. This is because the boost::thread_specific_ptr functionality will be increasingly used by Boost.Threads itself, so that proper cleanup will become essential in future versions of Boost.Threads.
Again, I don't understand why you need thread_specific_ptr within boost.threads so much.
To quote from a past posting: "The reasons [for using tss in the thread class's implementation] are two-fold: 1) The thread class becomes a handle class that holds a reference-counted pointer to a thread_data class. When a thread class is created, it gets access to the thread_data class for the thread using [TSS]. 2) As you might guess from the name of the thread_data class, there is other information associated with each thread; for instance, a thread id, a flag indicating whether the thread has been canceled (yes, there is an exception-based implementation of thread cancellation), etc." In other words, the thread class needs to associate thread-specific data with each thread, and the obvious way to do this is to use thread_specific_ptr.
Anyway, if you need thread_specific_ptr so much, maybe we could do away with two libraries, something like: 'thread' and 'thread_ext' or so.
In the thread, we should keep what was roughly before: - mutexes (don't tell me they need TLS) and scoped locks - thread class (no cleanup support) - xtime
In the thread_ext, include whatever needs thread_specific_ptr, and extra goodies - this will have the statically/dynamically linked issue.
I think this would be quite good in the long run, since there are so many libs/applications that only need basic thread support, and who really don't want an extra DLL added to the maintenance list.
As I mention above, I'm hoping to make the dll unnecessary (at least unnecessary for tss cleanup). Splitting everything into two libraries is probably a good approach if I don't succeed, however. Mike

I've just downloaded boost 1.31.0 but there is no mak file for BCB5. Where can I get it from ? I tried the BCB6.mak file but it uses the bcb6 compiler. I'll try renaming the bcb6 folder so it cannot be found and see what happens. Malcolm Smith MJ Freelancing http://www.mjfreelancing.com Borland Technology Partner --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.713 / Virus Database: 469 - Release Date: 30/06/2004

Nope, didn't work for me. Is there a BCB5 mak file ? Malcolm Smith MJ Freelancing http://www.mjfreelancing.com Borland Technology Partner -----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org]On Behalf Of Malcolm Smith Sent: Friday, 2 July 2004 19:43 To: boost@lists.boost.org Subject: [boost] regex under bcb5 I've just downloaded boost 1.31.0 but there is no mak file for BCB5. Where can I get it from ? I tried the BCB6.mak file but it uses the bcb6 compiler. I'll try renaming the bcb6 folder so it cannot be found and see what happens. Malcolm Smith MJ Freelancing http://www.mjfreelancing.com Borland Technology Partner --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.713 / Virus Database: 469 - Release Date: 30/06/2004 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost --- Incoming mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.713 / Virus Database: 469 - Release Date: 30/06/2004 --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.713 / Virus Database: 469 - Release Date: 30/06/2004
participants (5)
-
John Maddock
-
John Torjo
-
Malcolm Smith
-
Michael Glassford
-
Neal D. Becker