[log] Review-ready version in the Vault

After a long time of documenting, polishing and testing I'm glad to announce that Boost.Log has reached the level where public review request can be submitted. The automatic tests aren't entirely complete, however, the basic functionality is covered and most of what is not covered has been tried by hand. Major changes since my last publicly announced version: * Substantial documentation improvement. * Added several Windows-specific sinks: Event Log (simplified and advanced), Windows debugger and experimental Event Trace for Windows Vista and later. * Loggers now consist of a number of independent features that can be composed the way the user needs. User-defined features can be developed and injected into the mix. * Attribute value extractors improved. With the new extract function attribute values can be extracted from the attribute values view by employing lambda functors. * Some files and classes were moved or renamed to improve code clarity and shorten names. * A number of bugs fixed. * Added tests. The archive with the library source code, tests and docs is available in the Vault: http://tinyurl.com/cm9lum The online docs are also available on the SourceForge page: http://boost-log.sourceforge.net The latest code snapshot can be downloaded from CVS on the SourceForge project page: http://sourceforge.net/projects/boost-log The code should be compatible with Boost 1.38. Might also work with 1.37, but I didn't try. Comments are welcome.

On Sun, 08 Feb 2009 16:58:54 +0100, Andrey Semashev <andrey.semashev@gmail.com> wrote: Hi Andrey,
After a long time of documenting, polishing and testing I'm glad to announce that Boost.Log has reached the level where public review request can be submitted. The automatic tests aren't entirely complete, however, the basic functionality is covered and most of what is not covered has been tried by hand.
Major changes since my last publicly announced version:
these are all really great news! I especially look forward to test the Windows-specific sinks. Supporting operating system-specific logging functions including the Windows Event Log should give your library a boost as it's not an either/or question anymore between a platform-independent Boost library or utilizing operating system functions.
[...]The code should be compatible with Boost 1.38. Might also work with 1.37, but I didn't try.
I still use Boost 1.36.0. Building your library worked fine. I'll see in the coming days if I run into any problems. Boris

Hi Andrey,
The latest code snapshot can be downloaded from CVS on the SourceForge project page: http://sourceforge.net/projects/boost-log
I tried to build the current CVS HEAD of your library combined with the current SVN head of the Boost SVN Repository on Linux/x86 using gcc 4.3.3, but there were a number of test failures, apparently because of a missing header file "char_definitions.hpp". The build log is attached below. Do you have any idea what I'm doing wrong? Take care, Peter -*- mode: compilation; default-directory: "/usr/local/src/boost-log/" -*- Compilation started at Mon Feb 9 11:44:54 bjam -d2 lib.jam: No such file or directory Building Boost.Regex with the optional Unicode/ICU support disabled. Note: Please refer to the Boost.Regex documentation for more information Note: this is a strictly optional feature. ...patience... ...patience... ...found 2828 targets... ...updating 56 targets... gcc.compile.c++ libs/log/test/bin/attr_attribute_values_view.test/gcc-4.3.3/debug/link-static/run/attr_attribute_values_view.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/attr_attribute_values_view.test/gcc-4.3.3/debug/link-static/run/attr_attribute_values_view.o" "libs/log/test/run/attr_attribute_values_view.cpp" libs/log/test/run/attr_attribute_values_view.cpp:32:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/attr_attribute_values_view.cpp:57: error: `char_types' was not declared in this scope libs/log/test/run/attr_attribute_values_view.cpp:57: error: template argument 2 is invalid libs/log/test/run/attr_attribute_values_view.cpp: In member function `void construction<CharT>::test_method()': libs/log/test/run/attr_attribute_values_view.cpp:61: error: expected initializer before `<' token libs/log/test/run/attr_attribute_values_view.cpp:70: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:71: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:72: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:82: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:83: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:84: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:105: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:106: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:107: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:108: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:110: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:111: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:113: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:114: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:123: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:126: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:130: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:134: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp: At global scope: libs/log/test/run/attr_attribute_values_view.cpp:140: error: `char_types' was not declared in this scope libs/log/test/run/attr_attribute_values_view.cpp:140: error: template argument 2 is invalid libs/log/test/run/attr_attribute_values_view.cpp: In member function `void lookup<CharT>::test_method()': libs/log/test/run/attr_attribute_values_view.cpp:144: error: expected initializer before `<' token libs/log/test/run/attr_attribute_values_view.cpp:153: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:154: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:155: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:161: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:163: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:168: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:171: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:176: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:179: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:188: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:192: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:213: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:218: error: `data' has not been declared libs/log/test/run/attr_attribute_values_view.cpp:221: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/attr_attribute_values_view.test/gcc-4.3.3/debug/link-static/run/attr_attribute_values_view.o... ...skipped <plibs/log/test/bin/attr_attribute_values_view.test/gcc-4.3.3/debug/link-static>attr_attribute_values_view for lack of <plibs/log/test/bin/attr_attribute_values_view.test/gcc-4.3.3/debug/link-static>run/attr_attribute_values_view.o... ...skipped <plibs/log/test/bin/attr_attribute_values_view.test/gcc-4.3.3/debug/link-static>attr_attribute_values_view.run for lack of <plibs/log/test/bin/attr_attribute_values_view.test/gcc-4.3.3/debug/link-static>attr_attribute_values_view... gcc.compile.c++ libs/log/test/bin/form_message.test/gcc-4.3.3/debug/link-static/run/form_message.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/form_message.test/gcc-4.3.3/debug/link-static/run/form_message.o" "libs/log/test/run/form_message.cpp" libs/log/test/run/form_message.cpp:27:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/form_message.cpp:41: error: expected template-name before `<' token libs/log/test/run/form_message.cpp:41: error: expected `{' before `<' token libs/log/test/run/form_message.cpp:41: error: expected unqualified-id before `<' token libs/log/test/run/form_message.cpp:50: error: expected template-name before `<' token libs/log/test/run/form_message.cpp:50: error: expected `{' before `<' token libs/log/test/run/form_message.cpp:50: error: expected unqualified-id before `<' token libs/log/test/run/form_message.cpp:59: error: `char_types' was not declared in this scope libs/log/test/run/form_message.cpp:59: error: template argument 2 is invalid ...failed gcc.compile.c++ libs/log/test/bin/form_message.test/gcc-4.3.3/debug/link-static/run/form_message.o... ...skipped <plibs/log/test/bin/form_message.test/gcc-4.3.3/debug/link-static>form_message for lack of <plibs/log/test/bin/form_message.test/gcc-4.3.3/debug/link-static>run/form_message.o... ...skipped <plibs/log/test/bin/form_message.test/gcc-4.3.3/debug/link-static>form_message.run for lack of <plibs/log/test/bin/form_message.test/gcc-4.3.3/debug/link-static>form_message... gcc.compile.c++ libs/log/test/bin/attr_named_scope.test/gcc-4.3.3/debug/link-static/run/attr_named_scope.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/attr_named_scope.test/gcc-4.3.3/debug/link-static/run/attr_named_scope.o" "libs/log/test/run/attr_named_scope.cpp" libs/log/test/run/attr_named_scope.cpp:25:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/attr_named_scope.cpp:71: error: `char_types' was not declared in this scope libs/log/test/run/attr_named_scope.cpp:71: error: template argument 2 is invalid libs/log/test/run/attr_named_scope.cpp:151: error: `char_types' was not declared in this scope libs/log/test/run/attr_named_scope.cpp:151: error: template argument 2 is invalid libs/log/test/run/attr_named_scope.cpp:175: error: `char_types' was not declared in this scope libs/log/test/run/attr_named_scope.cpp:175: error: template argument 2 is invalid libs/log/test/run/attr_named_scope.cpp:191: error: `char_types' was not declared in this scope libs/log/test/run/attr_named_scope.cpp:191: error: template argument 2 is invalid ...failed gcc.compile.c++ libs/log/test/bin/attr_named_scope.test/gcc-4.3.3/debug/link-static/run/attr_named_scope.o... ...skipped <plibs/log/test/bin/attr_named_scope.test/gcc-4.3.3/debug/link-static>attr_named_scope for lack of <plibs/log/test/bin/attr_named_scope.test/gcc-4.3.3/debug/link-static>run/attr_named_scope.o... ...skipped <plibs/log/test/bin/attr_named_scope.test/gcc-4.3.3/debug/link-static>attr_named_scope.run for lack of <plibs/log/test/bin/attr_named_scope.test/gcc-4.3.3/debug/link-static>attr_named_scope... gcc.compile.c++ libs/log/test/bin/form_if.test/gcc-4.3.3/debug/link-static/run/form_if.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/form_if.test/gcc-4.3.3/debug/link-static/run/form_if.o" "libs/log/test/run/form_if.cpp" libs/log/test/run/form_if.cpp:30:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/form_if.cpp:38: error: `char_types' was not declared in this scope libs/log/test/run/form_if.cpp:38: error: template argument 2 is invalid libs/log/test/run/form_if.cpp: In member function `void conditional_formatting<CharT>::test_method()': libs/log/test/run/form_if.cpp:45: error: expected initializer before `<' token libs/log/test/run/form_if.cpp:51: error: `data' has not been declared libs/log/test/run/form_if.cpp:52: error: `data' has not been declared libs/log/test/run/form_if.cpp:61: error: `data' has not been declared libs/log/test/run/form_if.cpp:63: error: `data' has not been declared libs/log/test/run/form_if.cpp:65: error: `data' has not been declared libs/log/test/run/form_if.cpp:73: error: `data' has not been declared libs/log/test/run/form_if.cpp:75: error: `data' has not been declared libs/log/test/run/form_if.cpp:77: error: `data' has not been declared libs/log/test/run/form_if.cpp:83: error: `data' has not been declared libs/log/test/run/form_if.cpp:85: error: `data' has not been declared libs/log/test/run/form_if.cpp:89: error: `data' has not been declared libs/log/test/run/form_if.cpp:91: error: `data' has not been declared libs/log/test/run/form_if.cpp:99: error: `data' has not been declared libs/log/test/run/form_if.cpp:101: error: `data' has not been declared libs/log/test/run/form_if.cpp:105: error: `data' has not been declared libs/log/test/run/form_if.cpp:107: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/form_if.test/gcc-4.3.3/debug/link-static/run/form_if.o... ...skipped <plibs/log/test/bin/form_if.test/gcc-4.3.3/debug/link-static>form_if for lack of <plibs/log/test/bin/form_if.test/gcc-4.3.3/debug/link-static>run/form_if.o... ...skipped <plibs/log/test/bin/form_if.test/gcc-4.3.3/debug/link-static>form_if.run for lack of <plibs/log/test/bin/form_if.test/gcc-4.3.3/debug/link-static>form_if... gcc.compile.c++ libs/log/test/bin/form_attr.test/gcc-4.3.3/debug/link-static/run/form_attr.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/form_attr.test/gcc-4.3.3/debug/link-static/run/form_attr.o" "libs/log/test/run/form_attr.cpp" libs/log/test/run/form_attr.cpp:33:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/form_attr.cpp:59: error: `char_types' was not declared in this scope libs/log/test/run/form_attr.cpp:59: error: template argument 2 is invalid libs/log/test/run/form_attr.cpp: In member function `void default_formatting<CharT>::test_method()': libs/log/test/run/form_attr.cpp:66: error: expected initializer before `<' token libs/log/test/run/form_attr.cpp:73: error: `data' has not been declared libs/log/test/run/form_attr.cpp:74: error: `data' has not been declared libs/log/test/run/form_attr.cpp:75: error: `data' has not been declared libs/log/test/run/form_attr.cpp:83: error: `data' has not been declared libs/log/test/run/form_attr.cpp:83: error: `data' has not been declared libs/log/test/run/form_attr.cpp:84: error: `data' has not been declared libs/log/test/run/form_attr.cpp:91: error: `data' has not been declared libs/log/test/run/form_attr.cpp:91: error: `data' has not been declared libs/log/test/run/form_attr.cpp:92: error: `data' has not been declared libs/log/test/run/form_attr.cpp:99: error: `data' has not been declared libs/log/test/run/form_attr.cpp:99: error: `data' has not been declared libs/log/test/run/form_attr.cpp:100: error: `data' has not been declared libs/log/test/run/form_attr.cpp:108: error: `data' has not been declared libs/log/test/run/form_attr.cpp:109: error: `data' has not been declared libs/log/test/run/form_attr.cpp:117: error: `data' has not been declared libs/log/test/run/form_attr.cpp:117: error: `data' has not been declared libs/log/test/run/form_attr.cpp:117: error: `data' has not been declared libs/log/test/run/form_attr.cpp:118: error: `data' has not been declared libs/log/test/run/form_attr.cpp: At global scope: libs/log/test/run/form_attr.cpp:126: error: `char_types' was not declared in this scope libs/log/test/run/form_attr.cpp:126: error: template argument 2 is invalid libs/log/test/run/form_attr.cpp: In member function `void format_specification<CharT>::test_method()': libs/log/test/run/form_attr.cpp:133: error: expected initializer before `<' token libs/log/test/run/form_attr.cpp:139: error: `data' has not been declared libs/log/test/run/form_attr.cpp:140: error: `data' has not been declared libs/log/test/run/form_attr.cpp:147: error: `data' has not been declared libs/log/test/run/form_attr.cpp:147: error: `data' has not been declared libs/log/test/run/form_attr.cpp:147: error: `data' has not been declared libs/log/test/run/form_attr.cpp:147: error: `data' has not been declared libs/log/test/run/form_attr.cpp:148: error: `data' has not been declared libs/log/test/run/form_attr.cpp:150: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/form_attr.test/gcc-4.3.3/debug/link-static/run/form_attr.o... ...skipped <plibs/log/test/bin/form_attr.test/gcc-4.3.3/debug/link-static>form_attr for lack of <plibs/log/test/bin/form_attr.test/gcc-4.3.3/debug/link-static>run/form_attr.o... ...skipped <plibs/log/test/bin/form_attr.test/gcc-4.3.3/debug/link-static>form_attr.run for lack of <plibs/log/test/bin/form_attr.test/gcc-4.3.3/debug/link-static>form_attr... gcc.compile.c++ libs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static/run/attr_attribute_set.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static/run/attr_attribute_set.o" "libs/log/test/run/attr_attribute_set.cpp" libs/log/test/run/attr_attribute_set.cpp:25:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/attr_attribute_set.cpp:31: error: `char_types' was not declared in this scope libs/log/test/run/attr_attribute_set.cpp:31: error: template argument 2 is invalid libs/log/test/run/attr_attribute_set.cpp: In member function `void construction<CharT>::test_method()': libs/log/test/run/attr_attribute_set.cpp:34: error: expected initializer before `<' token libs/log/test/run/attr_attribute_set.cpp:48: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:49: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:58: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:59: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:60: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:62: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:65: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp: At global scope: libs/log/test/run/attr_attribute_set.cpp:73: error: `char_types' was not declared in this scope libs/log/test/run/attr_attribute_set.cpp:73: error: template argument 2 is invalid libs/log/test/run/attr_attribute_set.cpp: In member function `void lookup<CharT>::test_method()': libs/log/test/run/attr_attribute_set.cpp:76: error: expected initializer before `<' token libs/log/test/run/attr_attribute_set.cpp:84: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:85: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:88: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:92: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:97: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:102: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:106: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:118: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:123: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:126: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp: At global scope: libs/log/test/run/attr_attribute_set.cpp:130: error: `char_types' was not declared in this scope libs/log/test/run/attr_attribute_set.cpp:130: error: template argument 2 is invalid libs/log/test/run/attr_attribute_set.cpp: In member function `void insertion<CharT>::test_method()': libs/log/test/run/attr_attribute_set.cpp:133: error: expected initializer before `<' token libs/log/test/run/attr_attribute_set.cpp:144: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:147: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:152: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:155: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:161: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:164: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:171: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:172: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:173: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:175: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:182: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:185: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:188: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:202: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:206: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:210: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:224: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:228: error: `data' was not declared in this scope libs/log/test/run/attr_attribute_set.cpp:232: error: expected primary-expression before `(' token libs/log/test/run/attr_attribute_set.cpp:232: error: `data' is not a class or namespace libs/log/test/run/attr_attribute_set.cpp:237: error: `data' is not a class or namespace libs/log/test/run/attr_attribute_set.cpp: At global scope: libs/log/test/run/attr_attribute_set.cpp:243: error: `char_types' was not declared in this scope libs/log/test/run/attr_attribute_set.cpp:243: error: template argument 2 is invalid libs/log/test/run/attr_attribute_set.cpp: In member function `void erasure<CharT>::test_method()': libs/log/test/run/attr_attribute_set.cpp:246: error: expected initializer before `<' token libs/log/test/run/attr_attribute_set.cpp:255: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:256: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:257: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:262: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:264: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:266: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:271: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:279: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:280: error: `data' has not been declared libs/log/test/run/attr_attribute_set.cpp:281: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static/run/attr_attribute_set.o... ...skipped <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>attr_attribute_set for lack of <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>run/attr_attribute_set.o... ...skipped <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>attr_attribute_set.run for lack of <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>attr_attribute_set... gcc.compile.c++ libs/log/test/bin/util_attribute_value_extractor.test/gcc-4.3.3/debug/link-static/run/util_attribute_value_extractor.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/util_attribute_value_extractor.test/gcc-4.3.3/debug/link-static/run/util_attribute_value_extractor.o" "libs/log/test/run/util_attribute_value_extractor.cpp" libs/log/test/run/util_attribute_value_extractor.cpp:25:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/util_attribute_value_extractor.cpp:100: error: `char_types' was not declared in this scope libs/log/test/run/util_attribute_value_extractor.cpp:100: error: template argument 2 is invalid libs/log/test/run/util_attribute_value_extractor.cpp: In member function `void extractors_single_type<CharT>::test_method()': libs/log/test/run/util_attribute_value_extractor.cpp:104: error: expected initializer before `<' token libs/log/test/run/util_attribute_value_extractor.cpp:111: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:112: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:119: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:120: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:121: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:122: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:123: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:137: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp: At global scope: libs/log/test/run/util_attribute_value_extractor.cpp:155: error: `char_types' was not declared in this scope libs/log/test/run/util_attribute_value_extractor.cpp:155: error: template argument 2 is invalid libs/log/test/run/util_attribute_value_extractor.cpp: In member function `void extractors_multiple_types<CharT>::test_method()': libs/log/test/run/util_attribute_value_extractor.cpp:159: error: expected initializer before `<' token libs/log/test/run/util_attribute_value_extractor.cpp:167: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:168: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:175: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:176: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:177: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:191: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp: At global scope: libs/log/test/run/util_attribute_value_extractor.cpp:201: error: `char_types' was not declared in this scope libs/log/test/run/util_attribute_value_extractor.cpp:201: error: template argument 2 is invalid libs/log/test/run/util_attribute_value_extractor.cpp: In member function `void extract_function<CharT>::test_method()': libs/log/test/run/util_attribute_value_extractor.cpp:205: error: expected initializer before `<' token libs/log/test/run/util_attribute_value_extractor.cpp:213: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:214: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:223: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:226: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:230: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:231: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:234: error: `data' has not been declared libs/log/test/run/util_attribute_value_extractor.cpp:240: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/util_attribute_value_extractor.test/gcc-4.3.3/debug/link-static/run/util_attribute_value_extractor.o... ...skipped <plibs/log/test/bin/util_attribute_value_extractor.test/gcc-4.3.3/debug/link-static>util_attribute_value_extractor for lack of <plibs/log/test/bin/util_attribute_value_extractor.test/gcc-4.3.3/debug/link-static>run/util_attribute_value_extractor.o... ...skipped <plibs/log/test/bin/util_attribute_value_extractor.test/gcc-4.3.3/debug/link-static>util_attribute_value_extractor.run for lack of <plibs/log/test/bin/util_attribute_value_extractor.test/gcc-4.3.3/debug/link-static>util_attribute_value_extractor... gcc.compile.c++ libs/log/test/bin/form_format.test/gcc-4.3.3/debug/link-static/run/form_format.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/form_format.test/gcc-4.3.3/debug/link-static/run/form_format.o" "libs/log/test/run/form_format.cpp" libs/log/test/run/form_format.cpp:27:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/form_format.cpp:41: error: expected template-name before `<' token libs/log/test/run/form_format.cpp:41: error: expected `{' before `<' token libs/log/test/run/form_format.cpp:41: error: expected unqualified-id before `<' token libs/log/test/run/form_format.cpp:50: error: expected template-name before `<' token libs/log/test/run/form_format.cpp:50: error: expected `{' before `<' token libs/log/test/run/form_format.cpp:50: error: expected unqualified-id before `<' token libs/log/test/run/form_format.cpp:59: error: `char_types' was not declared in this scope libs/log/test/run/form_format.cpp:59: error: template argument 2 is invalid ...failed gcc.compile.c++ libs/log/test/bin/form_format.test/gcc-4.3.3/debug/link-static/run/form_format.o... ...skipped <plibs/log/test/bin/form_format.test/gcc-4.3.3/debug/link-static>form_format for lack of <plibs/log/test/bin/form_format.test/gcc-4.3.3/debug/link-static>run/form_format.o... ...skipped <plibs/log/test/bin/form_format.test/gcc-4.3.3/debug/link-static>form_format.run for lack of <plibs/log/test/bin/form_format.test/gcc-4.3.3/debug/link-static>form_format... gcc.compile.c++ libs/log/test/bin/filt_has_attr.test/gcc-4.3.3/debug/link-static/run/filt_has_attr.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/filt_has_attr.test/gcc-4.3.3/debug/link-static/run/filt_has_attr.o" "libs/log/test/run/filt_has_attr.cpp" libs/log/test/run/filt_has_attr.cpp:26:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/filt_has_attr.cpp:33: error: `char_types' was not declared in this scope libs/log/test/run/filt_has_attr.cpp:33: error: template argument 2 is invalid libs/log/test/run/filt_has_attr.cpp: In member function `void presence_check<CharT>::test_method()': libs/log/test/run/filt_has_attr.cpp:38: error: expected initializer before `<' token libs/log/test/run/filt_has_attr.cpp:45: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:46: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:47: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:52: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:55: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:58: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:61: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:64: error: `mpl' has not been declared libs/log/test/run/filt_has_attr.cpp:64: error: expected initializer before `<' token libs/log/test/run/filt_has_attr.cpp:65: error: `value_types' was not declared in this scope libs/log/test/run/filt_has_attr.cpp:65: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:68: error: `value_types' cannot appear in a constant-expression libs/log/test/run/filt_has_attr.cpp:68: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp: At global scope: libs/log/test/run/filt_has_attr.cpp:73: error: `char_types' was not declared in this scope libs/log/test/run/filt_has_attr.cpp:73: error: template argument 2 is invalid libs/log/test/run/filt_has_attr.cpp: In member function `void composition_check<CharT>::test_method()': libs/log/test/run/filt_has_attr.cpp:78: error: expected initializer before `<' token libs/log/test/run/filt_has_attr.cpp:87: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:90: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:91: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:95: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:95: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:100: error: `data' has not been declared libs/log/test/run/filt_has_attr.cpp:100: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/filt_has_attr.test/gcc-4.3.3/debug/link-static/run/filt_has_attr.o... ...skipped <plibs/log/test/bin/filt_has_attr.test/gcc-4.3.3/debug/link-static>filt_has_attr for lack of <plibs/log/test/bin/filt_has_attr.test/gcc-4.3.3/debug/link-static>run/filt_has_attr.o... ...skipped <plibs/log/test/bin/filt_has_attr.test/gcc-4.3.3/debug/link-static>filt_has_attr.run for lack of <plibs/log/test/bin/filt_has_attr.test/gcc-4.3.3/debug/link-static>filt_has_attr... gcc.compile.c++ libs/log/test/bin/form_date_time.test/gcc-4.3.3/debug/link-static/run/form_date_time.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/form_date_time.test/gcc-4.3.3/debug/link-static/run/form_date_time.o" "libs/log/test/run/form_date_time.cpp" libs/log/test/run/form_date_time.cpp:34:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/form_date_time.cpp:78: error: `char_types' was not declared in this scope libs/log/test/run/form_date_time.cpp:78: error: template argument 2 is invalid libs/log/test/run/form_date_time.cpp: In member function `void date_time<CharT>::test_method()': libs/log/test/run/form_date_time.cpp:85: error: expected initializer before `<' token libs/log/test/run/form_date_time.cpp:93: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:101: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:102: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:110: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:111: error: `data' has not been declared libs/log/test/run/form_date_time.cpp: At global scope: libs/log/test/run/form_date_time.cpp:120: error: `char_types' was not declared in this scope libs/log/test/run/form_date_time.cpp:120: error: template argument 2 is invalid libs/log/test/run/form_date_time.cpp: In member function `void date<CharT>::test_method()': libs/log/test/run/form_date_time.cpp:127: error: expected initializer before `<' token libs/log/test/run/form_date_time.cpp:135: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:143: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:144: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:152: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:153: error: `data' has not been declared libs/log/test/run/form_date_time.cpp: At global scope: libs/log/test/run/form_date_time.cpp:162: error: `char_types' was not declared in this scope libs/log/test/run/form_date_time.cpp:162: error: template argument 2 is invalid libs/log/test/run/form_date_time.cpp: In member function `void time_duration<CharT>::test_method()': libs/log/test/run/form_date_time.cpp:169: error: expected initializer before `<' token libs/log/test/run/form_date_time.cpp:177: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:185: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:186: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:194: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:195: error: `data' has not been declared libs/log/test/run/form_date_time.cpp: At global scope: libs/log/test/run/form_date_time.cpp:204: error: `char_types' was not declared in this scope libs/log/test/run/form_date_time.cpp:204: error: template argument 2 is invalid libs/log/test/run/form_date_time.cpp: In member function `void time_period<CharT>::test_method()': libs/log/test/run/form_date_time.cpp:211: error: expected initializer before `<' token libs/log/test/run/form_date_time.cpp:220: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:228: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:229: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:237: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:238: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:247: error: `data' has not been declared libs/log/test/run/form_date_time.cpp:250: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/form_date_time.test/gcc-4.3.3/debug/link-static/run/form_date_time.o... ...skipped <plibs/log/test/bin/form_date_time.test/gcc-4.3.3/debug/link-static>form_date_time for lack of <plibs/log/test/bin/form_date_time.test/gcc-4.3.3/debug/link-static>run/form_date_time.o... ...skipped <plibs/log/test/bin/form_date_time.test/gcc-4.3.3/debug/link-static>form_date_time.run for lack of <plibs/log/test/bin/form_date_time.test/gcc-4.3.3/debug/link-static>form_date_time... gcc.compile.c++ libs/log/test/bin/core.test/gcc-4.3.3/debug/link-static/run/core.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/core.test/gcc-4.3.3/debug/link-static/run/core.o" "libs/log/test/run/core.cpp" libs/log/test/run/core.cpp:33:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/core.cpp:82: error: `char_types' was not declared in this scope libs/log/test/run/core.cpp:82: error: template argument 2 is invalid libs/log/test/run/core.cpp: In member function `void filtering<CharT>::test_method()': libs/log/test/run/core.cpp:87: error: expected initializer before `<' token libs/log/test/run/core.cpp:93: error: `data' has not been declared libs/log/test/run/core.cpp:94: error: `data' has not been declared libs/log/test/run/core.cpp:105: error: `data' has not been declared libs/log/test/run/core.cpp:106: error: `data' has not been declared libs/log/test/run/core.cpp:107: error: `data' has not been declared libs/log/test/run/core.cpp:108: error: `data' has not been declared libs/log/test/run/core.cpp:114: error: `data' has not been declared libs/log/test/run/core.cpp:117: error: `data' has not been declared libs/log/test/run/core.cpp:118: error: `data' has not been declared libs/log/test/run/core.cpp:119: error: `data' has not been declared libs/log/test/run/core.cpp:120: error: `data' has not been declared libs/log/test/run/core.cpp:124: error: `data' has not been declared libs/log/test/run/core.cpp:128: error: `data' has not been declared libs/log/test/run/core.cpp:129: error: `data' has not been declared libs/log/test/run/core.cpp:130: error: `data' has not been declared libs/log/test/run/core.cpp:131: error: `data' has not been declared libs/log/test/run/core.cpp:138: error: `data' has not been declared libs/log/test/run/core.cpp:142: error: `data' has not been declared libs/log/test/run/core.cpp:143: error: `data' has not been declared libs/log/test/run/core.cpp:144: error: `data' has not been declared libs/log/test/run/core.cpp:145: error: `data' has not been declared libs/log/test/run/core.cpp:149: error: `data' has not been declared libs/log/test/run/core.cpp:152: error: `data' has not been declared libs/log/test/run/core.cpp:153: error: `data' has not been declared libs/log/test/run/core.cpp:154: error: `data' has not been declared libs/log/test/run/core.cpp:155: error: `data' has not been declared libs/log/test/run/core.cpp:161: error: `data' has not been declared libs/log/test/run/core.cpp:165: error: `data' has not been declared libs/log/test/run/core.cpp:171: error: `data' has not been declared libs/log/test/run/core.cpp:172: error: `data' has not been declared libs/log/test/run/core.cpp:173: error: `data' has not been declared libs/log/test/run/core.cpp:174: error: `data' has not been declared libs/log/test/run/core.cpp:178: error: `data' has not been declared libs/log/test/run/core.cpp:179: error: `data' has not been declared libs/log/test/run/core.cpp:180: error: `data' has not been declared libs/log/test/run/core.cpp:181: error: `data' has not been declared libs/log/test/run/core.cpp: At global scope: libs/log/test/run/core.cpp:214: error: `char_types' was not declared in this scope libs/log/test/run/core.cpp:214: error: template argument 2 is invalid libs/log/test/run/core.cpp: In member function `void attributes<CharT>::test_method()': libs/log/test/run/core.cpp:219: error: expected initializer before `<' token libs/log/test/run/core.cpp:226: error: `data' has not been declared libs/log/test/run/core.cpp:232: error: `data' has not been declared libs/log/test/run/core.cpp:233: error: `data' has not been declared libs/log/test/run/core.cpp:238: error: `data' has not been declared libs/log/test/run/core.cpp:242: error: `data' has not been declared libs/log/test/run/core.cpp:248: error: `data' has not been declared libs/log/test/run/core.cpp:249: error: `data' has not been declared libs/log/test/run/core.cpp:250: error: `data' has not been declared libs/log/test/run/core.cpp:251: error: `data' has not been declared libs/log/test/run/core.cpp: At global scope: libs/log/test/run/core.cpp:278: error: `char_types' was not declared in this scope libs/log/test/run/core.cpp:278: error: template argument 2 is invalid libs/log/test/run/core.cpp: In member function `void recursive_open_record<CharT>::test_method()': libs/log/test/run/core.cpp:283: error: expected initializer before `<' token libs/log/test/run/core.cpp:289: error: `data' has not been declared libs/log/test/run/core.cpp:292: error: `data' has not been declared libs/log/test/run/core.cpp:306: error: `data' has not been declared libs/log/test/run/core.cpp:307: error: `data' has not been declared libs/log/test/run/core.cpp:308: error: `data' has not been declared libs/log/test/run/core.cpp:309: error: `data' has not been declared libs/log/test/run/core.cpp:314: error: `data' has not been declared libs/log/test/run/core.cpp:315: error: `data' has not been declared libs/log/test/run/core.cpp:316: error: `data' has not been declared libs/log/test/run/core.cpp:317: error: `data' has not been declared libs/log/test/run/core.cpp:332: error: `data' has not been declared libs/log/test/run/core.cpp:333: error: `data' has not been declared libs/log/test/run/core.cpp:334: error: `data' has not been declared libs/log/test/run/core.cpp:335: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/core.test/gcc-4.3.3/debug/link-static/run/core.o... ...skipped <plibs/log/test/bin/core.test/gcc-4.3.3/debug/link-static>core for lack of <plibs/log/test/bin/core.test/gcc-4.3.3/debug/link-static>run/core.o... ...skipped <plibs/log/test/bin/core.test/gcc-4.3.3/debug/link-static>core.run for lack of <plibs/log/test/bin/core.test/gcc-4.3.3/debug/link-static>core... gcc.compile.c++ libs/log/test/bin/form_named_scope.test/gcc-4.3.3/debug/link-static/run/form_named_scope.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/form_named_scope.test/gcc-4.3.3/debug/link-static/run/form_named_scope.o" "libs/log/test/run/form_named_scope.cpp" libs/log/test/run/form_named_scope.cpp:30:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/form_named_scope.cpp:44: error: expected template-name before `<' token libs/log/test/run/form_named_scope.cpp:44: error: expected `{' before `<' token libs/log/test/run/form_named_scope.cpp:44: error: expected unqualified-id before `<' token libs/log/test/run/form_named_scope.cpp:56: error: expected template-name before `<' token libs/log/test/run/form_named_scope.cpp:56: error: expected `{' before `<' token libs/log/test/run/form_named_scope.cpp:56: error: expected unqualified-id before `<' token libs/log/test/run/form_named_scope.cpp:68: error: `char_types' was not declared in this scope libs/log/test/run/form_named_scope.cpp:68: error: template argument 2 is invalid ...failed gcc.compile.c++ libs/log/test/bin/form_named_scope.test/gcc-4.3.3/debug/link-static/run/form_named_scope.o... ...skipped <plibs/log/test/bin/form_named_scope.test/gcc-4.3.3/debug/link-static>form_named_scope for lack of <plibs/log/test/bin/form_named_scope.test/gcc-4.3.3/debug/link-static>run/form_named_scope.o... ...skipped <plibs/log/test/bin/form_named_scope.test/gcc-4.3.3/debug/link-static>form_named_scope.run for lack of <plibs/log/test/bin/form_named_scope.test/gcc-4.3.3/debug/link-static>form_named_scope... gcc.compile.c++ libs/log/test/bin/filt_attr.test/gcc-4.3.3/debug/link-static/run/filt_attr.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/filt_attr.test/gcc-4.3.3/debug/link-static/run/filt_attr.o" "libs/log/test/run/filt_attr.cpp" libs/log/test/run/filt_attr.cpp:30:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/filt_attr.cpp:37: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:37: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void general_conditions<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:42: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:49: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:50: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:51: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:56: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:59: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:62: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:65: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:68: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:71: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:74: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:77: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:83: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:88: error: `data' has not been declared libs/log/test/run/filt_attr.cpp: At global scope: libs/log/test/run/filt_attr.cpp:94: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:94: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void in_range_check<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:99: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:106: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:107: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:108: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:113: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:116: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:119: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:122: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:125: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:133: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:140: error: `data' has not been declared libs/log/test/run/filt_attr.cpp: At global scope: libs/log/test/run/filt_attr.cpp:174: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:174: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void satisfies_check<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:179: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:186: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:187: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:188: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:196: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:204: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:208: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:212: error: `data' has not been declared libs/log/test/run/filt_attr.cpp: At global scope: libs/log/test/run/filt_attr.cpp:218: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:218: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void begins_with_check<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:223: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:230: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:231: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:232: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:237: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:240: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:243: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:246: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:249: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:252: error: `data' has not been declared libs/log/test/run/filt_attr.cpp: At global scope: libs/log/test/run/filt_attr.cpp:257: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:257: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void ends_with_check<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:262: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:269: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:270: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:271: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:276: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:279: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:282: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:285: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:288: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:291: error: `data' has not been declared libs/log/test/run/filt_attr.cpp: At global scope: libs/log/test/run/filt_attr.cpp:296: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:296: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void contains_check<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:301: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:308: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:309: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:310: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:315: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:318: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:321: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:324: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:327: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:330: error: `data' has not been declared libs/log/test/run/filt_attr.cpp: At global scope: libs/log/test/run/filt_attr.cpp:335: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:335: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void matches_check<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:340: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:347: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:348: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:349: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:354: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:357: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:361: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:364: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:367: error: `data' has not been declared libs/log/test/run/filt_attr.cpp: At global scope: libs/log/test/run/filt_attr.cpp:372: error: `char_types' was not declared in this scope libs/log/test/run/filt_attr.cpp:372: error: template argument 2 is invalid libs/log/test/run/filt_attr.cpp: In member function `void composition_check<CharT>::test_method()': libs/log/test/run/filt_attr.cpp:377: error: expected initializer before `<' token libs/log/test/run/filt_attr.cpp:386: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:389: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:390: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:394: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:394: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:399: error: `data' has not been declared libs/log/test/run/filt_attr.cpp:399: error: `data' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/filt_attr.test/gcc-4.3.3/debug/link-static/run/filt_attr.o... ...skipped <plibs/log/test/bin/filt_attr.test/gcc-4.3.3/debug/link-static>filt_attr for lack of <plibs/log/test/bin/filt_attr.test/gcc-4.3.3/debug/link-static>run/filt_attr.o... ...skipped <plibs/log/test/bin/filt_attr.test/gcc-4.3.3/debug/link-static>filt_attr.run for lack of <plibs/log/test/bin/filt_attr.test/gcc-4.3.3/debug/link-static>filt_attr... gcc.compile.c++ libs/log/test/bin/util_slim_string.test/gcc-4.3.3/debug/link-static/run/util_slim_string.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -c -o "libs/log/test/bin/util_slim_string.test/gcc-4.3.3/debug/link-static/run/util_slim_string.o" "libs/log/test/run/util_slim_string.cpp" libs/log/test/run/util_slim_string.cpp:25:32: error: char_definitions.hpp: No such file or directory libs/log/test/run/util_slim_string.cpp:43: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:43: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void constructors<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:45: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:50: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:76: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:76: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void copies<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:78: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:83: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:103: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:103: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void swapping<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:105: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:110: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:111: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:112: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:113: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:117: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:120: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:125: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:128: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:134: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:134: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void streaming_output<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:136: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:142: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:147: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:151: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:151: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void substrs<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:153: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:158: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:177: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:177: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void comparison<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:179: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:184: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:186: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:194: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:197: error: `data_t' was not declared in this scope libs/log/test/run/util_slim_string.cpp:200: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:206: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:211: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:212: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:213: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:214: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:215: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:216: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:217: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:220: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:221: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:222: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:223: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:224: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:225: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:226: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:232: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:232: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void finds<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:234: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:240: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:241: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:243: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:243: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:244: error: `data_t' was not declared in this scope libs/log/test/run/util_slim_string.cpp:244: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:245: error: `data_t' was not declared in this scope libs/log/test/run/util_slim_string.cpp:245: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:246: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:246: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:248: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:248: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:249: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:249: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:252: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:252: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:256: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:256: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void rfinds<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:258: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:264: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:265: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:267: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:267: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:268: error: `data_t' was not declared in this scope libs/log/test/run/util_slim_string.cpp:268: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:269: error: `data_t' was not declared in this scope libs/log/test/run/util_slim_string.cpp:269: error: `data_t' is not a class or namespace libs/log/test/run/util_slim_string.cpp:270: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:270: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:272: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:272: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:273: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:273: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:276: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:276: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:280: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:280: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void find_first_ofs<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:282: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:288: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:289: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:295: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:298: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:298: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:301: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:301: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:303: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:303: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:307: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:307: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:311: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:311: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void find_last_ofs<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:313: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:319: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:320: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:326: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:329: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:329: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:332: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:332: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:334: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:334: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:338: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:338: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:343: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:343: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void find_first_not_ofs<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:345: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:351: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:352: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:361: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:367: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:367: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:369: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:369: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:373: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:373: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp: At global scope: libs/log/test/run/util_slim_string.cpp:377: error: `char_types' was not declared in this scope libs/log/test/run/util_slim_string.cpp:377: error: template argument 2 is invalid libs/log/test/run/util_slim_string.cpp: In member function `void find_last_not_ofs<CharT>::test_method()': libs/log/test/run/util_slim_string.cpp:379: error: expected initializer before `<' token libs/log/test/run/util_slim_string.cpp:385: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:386: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:397: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:403: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:403: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:405: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:405: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:409: error: `data_t' has not been declared libs/log/test/run/util_slim_string.cpp:409: error: `data_t' has not been declared ...failed gcc.compile.c++ libs/log/test/bin/util_slim_string.test/gcc-4.3.3/debug/link-static/run/util_slim_string.o... ...skipped <plibs/log/test/bin/util_slim_string.test/gcc-4.3.3/debug/link-static>util_slim_string for lack of <plibs/log/test/bin/util_slim_string.test/gcc-4.3.3/debug/link-static>run/util_slim_string.o... ...skipped <plibs/log/test/bin/util_slim_string.test/gcc-4.3.3/debug/link-static>util_slim_string.run for lack of <plibs/log/test/bin/util_slim_string.test/gcc-4.3.3/debug/link-static>util_slim_string... ...failed updating 14 targets... ...skipped 42 targets... Compilation exited abnormally with code 1 at Mon Feb 9 11:46:53

Peter Simons wrote:
Hi Andrey,
The latest code snapshot can be downloaded from CVS on the SourceForge project page: http://sourceforge.net/projects/boost-log
I tried to build the current CVS HEAD of your library combined with the current SVN head of the Boost SVN Repository on Linux/x86 using gcc 4.3.3, but there were a number of test failures, apparently because of a missing header file "char_definitions.hpp". The build log is attached below. Do you have any idea what I'm doing wrong?
This looks strange. I'm using GCC 4.3.2 and it works fine. For some reason bjam doesn't append -I$(BOOST_ROOT)/libs/log/test/common to GCC command line. Could that be because BOOST_ROOT is not defined?

Hi Andrey,
For some reason bjam doesn't append -I$(BOOST_ROOT)/libs/log/test/common to GCC command line.
now I got it. The parameter was added to the command line, alright, but it didn't do anything because the assumption that Boost.Log has been copied into the rest of the Boost source code is wrong, i.e. my "test/common" directory is not underneath $BOOST_ROOT. The following patch fixes the problem. --- a/libs/log/test/Jamfile.v2 +++ b/libs/log/test/Jamfile.v2 @@ -8,7 +8,7 @@ import testing ; project : requirements - <include>$(BOOST_ROOT)/libs/log/test/common + <include>common <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE <library>/boost/log//boost_log With that change applied, all tests but one succeed -- "attr_attribute_set" still doesn't seem to compile. The build log is attached to this e-mail. To you have any idea what the problem might be? Take care, Peter lib.jam: No such file or directory Building Boost.Regex with the optional Unicode/ICU support disabled. Note: Please refer to the Boost.Regex documentation for more information Note: this is a strictly optional feature. ...patience... ...patience... ...found 3851 targets... ...updating 4 targets... gcc.compile.c++ libs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static/run/attr_attribute_set.o /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_pair.h: In member function "std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >& std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >::operator=(const std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >&)": /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_pair.h:73: instantiated from "void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >, _Alloc = std::allocator<std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> > >]" /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_vector.h:694: instantiated from "void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >, _Alloc = std::allocator<std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> > >]" libs/log/test/run/attr_attribute_set.cpp:171: instantiated from "void insertion<CharT>::test_method() [with CharT = wchar_t]" libs/log/test/run/attr_attribute_set.cpp:130: instantiated from "static void insertion_invoker::run(boost::type<Exception>*) [with TestType = wchar_t]" /usr/local/src/boost-current/boost/test/unit_test_suite_impl.hpp:357: instantiated from "void boost::unit_test::ut_detail::test_case_template_invoker<TestCaseTemplate, TestType>::operator()() [with TestCaseTemplate = insertion_invoker, TestType = wchar_t]" /usr/local/src/boost-current/boost/test/utils/callback.hpp:56: instantiated from "boost::unit_test::ut_detail::unused boost::unit_test::ut_detail::invoker<boost::unit_test::ut_detail::unused>::invoke(Functor&) [with Functor = boost::unit_test::ut_detail::test_case_template_invoker<insertion_invoker, wchar_t>]" /usr/local/src/boost-current/boost/test/utils/callback.hpp:89: instantiated from "R boost::unit_test::ut_detail::callback0_impl_t<R, Functor>::invoke() [with R = boost::unit_test::ut_detail::unused, Functor = boost::unit_test::ut_detail::test_case_template_invoker<insertion_invoker, wchar_t>]" libs/log/test/run/attr_attribute_set.cpp:289: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_pair.h:73: error: non-static const member "const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> > std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >::first", can't use default assignment operator /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/vector.tcc: In member function "void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >, _Alloc = std::allocator<std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> > >]": /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/vector.tcc:299: note: synthesized method "std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >& std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >::operator=(const std::pair<const boost::log_st::basic_slim_string<wchar_t, std::char_traits<wchar_t> >, boost::shared_ptr<boost::log_st::attribute> >&)" first required here /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_pair.h: In member function "std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >& std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >::operator=(const std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >&)": /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_pair.h:73: instantiated from "void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >, _Alloc = std::allocator<std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> > >]" /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_vector.h:694: instantiated from "void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >, _Alloc = std::allocator<std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> > >]" libs/log/test/run/attr_attribute_set.cpp:171: instantiated from "void insertion<CharT>::test_method() [with CharT = char]" libs/log/test/run/attr_attribute_set.cpp:130: instantiated from "static void insertion_invoker::run(boost::type<Exception>*) [with TestType = char]" /usr/local/src/boost-current/boost/test/unit_test_suite_impl.hpp:357: instantiated from "void boost::unit_test::ut_detail::test_case_template_invoker<TestCaseTemplate, TestType>::operator()() [with TestCaseTemplate = insertion_invoker, TestType = char]" /usr/local/src/boost-current/boost/test/utils/callback.hpp:56: instantiated from "boost::unit_test::ut_detail::unused boost::unit_test::ut_detail::invoker<boost::unit_test::ut_detail::unused>::invoke(Functor&) [with Functor = boost::unit_test::ut_detail::test_case_template_invoker<insertion_invoker, char>]" /usr/local/src/boost-current/boost/test/utils/callback.hpp:89: instantiated from "R boost::unit_test::ut_detail::callback0_impl_t<R, Functor>::invoke() [with R = boost::unit_test::ut_detail::unused, Functor = boost::unit_test::ut_detail::test_case_template_invoker<insertion_invoker, char>]" libs/log/test/run/attr_attribute_set.cpp:289: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/stl_pair.h:73: error: non-static const member "const boost::log_st::basic_slim_string<char, std::char_traits<char> > std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >::first", can't use default assignment operator /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/vector.tcc: In member function "void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >, _Alloc = std::allocator<std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> > >]": /usr/lib/gcc/i686-pc-linux-gnu/4.3.3/../../../../include/c++/4.3.3/bits/vector.tcc:299: note: synthesized method "std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >& std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >::operator=(const std::pair<const boost::log_st::basic_slim_string<char, std::char_traits<char> >, boost::shared_ptr<boost::log_st::attribute> >&)" first required here "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fpermissive -DBOOST_FILESYSTEM_STATIC_LINK=1 -DBOOST_LOG_NO_THREADS -DBOOST_SYSTEM_STATIC_LINK=1 -DBOOST_TEST_NO_AUTO_LINK=1 -DDATE_TIME_INLINE -I"." -I"/usr/local/src/boost-current" -I"libs/log/test/common" -c -o "libs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static/run/attr_attribute_set.o" "libs/log/test/run/attr_attribute_set.cpp" ...failed gcc.compile.c++ libs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static/run/attr_attribute_set.o... ...skipped <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>attr_attribute_set for lack of <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>run/attr_attribute_set.o... ...skipped <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>attr_attribute_set.run for lack of <plibs/log/test/bin/attr_attribute_set.test/gcc-4.3.3/debug/link-static>attr_attribute_set... ...failed updating 1 target... ...skipped 3 targets...

Peter Simons wrote:
Hi Andrey,
For some reason bjam doesn't append -I$(BOOST_ROOT)/libs/log/test/common to GCC command line.
now I got it. The parameter was added to the command line, alright, but it didn't do anything because the assumption that Boost.Log has been copied into the rest of the Boost source code is wrong, i.e. my "test/common" directory is not underneath $BOOST_ROOT. The following patch fixes the problem.
--- a/libs/log/test/Jamfile.v2 +++ b/libs/log/test/Jamfile.v2 @@ -8,7 +8,7 @@ import testing ;
project : requirements - <include>$(BOOST_ROOT)/libs/log/test/common + <include>common <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE <library>/boost/log//boost_log
Great! I wasn't sure from which directory bjam would start looking for relative paths, so I wrote the complete one.
With that change applied, all tests but one succeed -- "attr_attribute_set" still doesn't seem to compile. The build log is attached to this e-mail. To you have any idea what the problem might be?
The problem is the GCC's STL implementation specifics. Looks like it uses assignment to put an element into a vector, which prevents from using const types as the element members (std::pair in this case). I'm using STLPort, that's why this one went unnoticed. Fixed both the test and the Jamfile in CVS. Thanks for your feedback!

Hi, I have just started to read the documentation, and it is not easy to make the distinction between a elements in the library and the others. Can I suggest to rename the namesapce alias? Instead of namespace logging = boost::log; namespace sinks = boost::log::sinks; namespace src = boost::log::sources; namespace fmt = boost::log::formatters; namespace flt = boost::log::filters; namespace attrs = boost::log::attributes; use namespace blog = boost::log; namespace blsinks = boost::log::sinks; namespace blsrc = boost::log::sources; namespace blfmt = boost::log::formatters; namespace blflt = boost::log::filters; namespace blattrs = boost::log::attributes; So every thing starting with bl is an element of the library. I have some innocent questions: * Is logging thread-safe? * If yes, are the lines interleaved as it is the case for output streams? * If not could you point out how and where in the implementation this is handled? Thanks, Vicente

----- Original Message ----- From: "vicente.botet" <vicente.botet@wanadoo.fr> To: <boost@lists.boost.org> Sent: Wednesday, February 11, 2009 11:28 AM Subject: Re: [boost] [log] Review-ready version in the Vault
I have some innocent questions: * Is logging thread-safe? * If yes, are the lines interleaved as it is the case for output streams? * If not could you point out how and where in the implementation this is handled?
Hi again, well i have found some anwers to my questions on the document. I'll come back later on. How a log record is recognized, i.e. I don't see std::endl neither std::flush are used in the examples. How many lines result in the following example if condifiton is true (2 or 3) src::logger_mt& lg = my_logger::get(); if (lg.open_record()) { lg.strm() << "Hello "; lg.strm() << "world!"; } // do something if (condition) { if (lg.open_record()) lg.strm() << "Bye!"; } Can other logs be interleaved between "Hello " , "world!" and Bye in a multi threaded program? Thanks, Vicente

----- Original Message ----- From: "vicente.botet" <vicente.botet@wanadoo.fr> To: <boost@lists.boost.org> Sent: Wednesday, February 11, 2009 4:46 PM Subject: Re: [boost] [log] Review-ready version in the Vault
----- Original Message ----- From: "vicente.botet" <vicente.botet@wanadoo.fr> To: <boost@lists.boost.org> Sent: Wednesday, February 11, 2009 11:28 AM Subject: Re: [boost] [log] Review-ready version in the Vault
I have some innocent questions: * Is logging thread-safe? * If yes, are the lines interleaved as it is the case for output streams? * If not could you point out how and where in the implementation this is handled?
Hi again,
well i have found some anwers to my questions on the document. I'll come back later on.
Oh, I forget, Bravo! Excellent documentation. Reading the code I see a lot of try{ // } catch (...){ // Something has gone wrong. As the library should impose minimum influence // on the user's code, we simply mimic here that the record is not needed. } Does it mean that the application is unable to know when things go wrong? I'm mainly interested on how the library behaves on the context of multi threaded programs, performances, ... A trivial question, are all the sources associated to all the sinks? If this is the case, how the core is made thread-safe, a single mutex, Which operations will occur more often read-only or write? It is worth to use a shared_mutex? Why don't let the user the ability of instantiating cores? If I have understood on multi threaded applications we don't need to always use logger_mt but we need to use synchronous_sink or asynchronous_sink. The single difference between synchronous_sink and asynchronous_sink is that the later will do the formating and writing later on on an other thread, isn't it? In both cases there is a mutex associated to the sink. This mutex could be the bottleneck of the system, only one mutex resource for all the user threads. Another approach for the asynchronous_sink could be to use a queue of log records for each thread (thread specific storage). Each log records must be timestamped with the creation date and a monotonic counter (time is not enough fine grained) and as the queue is specific to the thread no need to use a mutex. On the other side there is a concentrator which takes one by one the elements ordered by the timestamp+counter. So only the current thread can push on this queue because is specific to the thread. There is a single thread, the concentrator that pops from these queue. In this context we can ensure thread safety without locking as far as the queue has at least two messages. (The Fork/Join Java framework and Boost.ThreadPool use this technique). There is one more issue here, because all the threads can log, while on the ThreadPool only the threads in the pool can add tasks on the queue of the worker thread. So the concentrator needs to have access to all the thread_specific storage. The Boost.Interthreads library defines a thread_specific_shared_ptr class which extends the thread_specific_ptr class with synchronized access to thread_specific_shared_ptr of a thread from another, either giving the thread::id or iterating on a map : thread::id -> shared_ptr<stored_data>. I have not done yet any performances comparation, but I think that the bottleneck is avoided. In addition this will solve the issue with log records that are weakly ordered in a multithreaded applications. If I have time before the review I'll try to use this approach to define an strict_asynchronous_sink which will ensure strict order and minimize the contention. Have you some performance test I can use to compare? Thanks, Vicente

vicente.botet wrote:
Oh, I forget, Bravo! Excellent documentation.
Thanks. :)
Reading the code I see a lot of
try{ // } catch (...){ // Something has gone wrong. }
Does it mean that the application is unable to know when things go wrong?
Yes. Although extremely useful, logging is an auxiliary feature of the application, so it must not influence business logic. That is, users should not be bothered to wrap every log statement in a try/catch block.
I'm mainly interested on how the library behaves on the context of multi threaded programs, performances, ...
A trivial question, are all the sources associated to all the sinks?
Sources are not associated with sinks directly. A log record from any source may go to any one or several sinks. Which sinks will receive the record is entirely decided by filters.
If this is the case, how the core is made thread-safe, a single mutex, Which operations will occur more often read-only or write? It is worth to use a shared_mutex?
I assume that pushing log records through the core is a much more frequent operation than, say, registering sinks, changing filters or adding global attributes. Pushing records requires only read access to the core (well, to the thread-shared part of it, that is). That is why shared_mutex allows to significantly reduce contention for the major case.
Why don't let the user the ability of instantiating cores?
Because the core contains all the set up of the library. Sources and some other parts of the library rely on that it is a singleton, which allows to simplify library interface significantly.
If I have understood on multi threaded applications we don't need to always use logger_mt but we need to use synchronous_sink or asynchronous_sink.
You only have to use *_mt loggers if the logger may be used by several threads simultaneously. In all other cases regular loggers are a better choice, since they are faster. As for sinks, it is the sink backend who decides. All sink backends provided by the library out of box will, indeed, require you to use either synchronous_sink or asynchronous_sink in multithreading environment. However, it is possible to create a backend that will not require that (for example, if the thread synchronization is done somewhere else, not in the sink frontend).
The single difference between synchronous_sink and asynchronous_sink is that the later will do the formating and writing later on on an other thread, isn't it? In both cases there is a mutex associated to the sink. This mutex could be the bottleneck of the system, only one mutex resource for all the user threads.
Remember that the mutex is only associated to a single sink. Writing to different sinks can be concurrent. Theoretically, the logging core can employ some clever scheduling between sinks, but this is not currently done. As for asynchronous sink frontend, the mutex is only needed to protect the queue of records for the dedicated thread. I would happily use some lock-free queue for this purpose, but Boost doesn't have one and I don't feel confident to implement one. I plan to add support for Intel TBB later.
Another approach for the asynchronous_sink could be to use a queue of log records for each thread (thread specific storage). Each log records must be timestamped with the creation date and a monotonic counter (time is not enough fine grained) and as the queue is specific to the thread no need to use a mutex. On the other side there is a concentrator which takes one by one the elements ordered by the timestamp+counter.
Something like that is planned in the future. However, I was going to use a single queue to interleave records during pushes.
So only the current thread can push on this queue because is specific to the thread. There is a single thread, the concentrator that pops from these queue. In this context we can ensure thread safety without locking as far as the queue has at least two messages. (The Fork/Join Java framework and Boost.ThreadPool use this technique).
You still need to synchronize pushes and pops, no matter how many queues you use. You do have two threads accessing the same queue anyway. While this will surely reduce contention, it is not lock-free.
There is one more issue here, because all the threads can log, while on the ThreadPool only the threads in the pool can add tasks on the queue of the worker thread. So the concentrator needs to have access to all the thread_specific storage.
The Boost.Interthreads library defines a thread_specific_shared_ptr class which extends the thread_specific_ptr class with synchronized access to thread_specific_shared_ptr of a thread from another, either giving the thread::id or iterating on a map : thread::id -> shared_ptr<stored_data>.
I have not done yet any performances comparation, but I think that the bottleneck is avoided.
Looking forward to see this library in Boost! The idea of separate queues, along with lock-free queue from TBB, looks very appealing.
In addition this will solve the issue with log records that are weakly ordered in a multithreaded applications.
If I have time before the review I'll try to use this approach to define an strict_asynchronous_sink which will ensure strict order and minimize the contention. Have you some performance test I can use to compare?
No, I haven't done any dedicated performance tests yet. I will try to produce something a bit later.

----- Original Message ----- From: "Andrey Semashev" <andrey.semashev@gmail.com> To: <boost@lists.boost.org> Sent: Wednesday, February 11, 2009 9:10 PM Subject: Re: [boost] [log] Review-ready version in the Vault
Reading the code I see a lot of
try{ // } catch (...){ // Something has gone wrong. }
Does it mean that the application is unable to know when things go wrong?
Yes. Although extremely useful, logging is an auxiliary feature of the application, so it must not influence business logic. That is, users should not be bothered to wrap every log statement in a try/catch block.
IMO, it is up to the application to decide what to do with exceptional cases. The log library could catch its own exceptions, but not the user exceptions, and in any case let the user think that a log has been done when it is not the case.
I'm mainly interested on how the library behaves on the context of multi threaded programs, performances, ...
A trivial question, are all the sources associated to all the sinks?
Sources are not associated with sinks directly. A log record from any source may go to any one or several sinks. Which sinks will receive the record is entirely decided by filters.
So we can consider that sources + core + sinks form a single "log".
If this is the case, how the core is made thread-safe, a single mutex, Which operations will occur more often read-only or write? It is worth to use a shared_mutex?
I assume that pushing log records through the core is a much more frequent operation than, say, registering sinks, changing filters or adding global attributes. Pushing records requires only read access to the core (well, to the thread-shared part of it, that is). That is why shared_mutex allows to significantly reduce contention for the major case.
Ok, I see the shared_mutex.
Why don't let the user the ability of instantiating cores?
Because the core contains all the set up of the library. Sources and some other parts of the library rely on that it is a singleton, which allows to simplify library interface significantly.
So the BoostLog library consist of a single log with multiple sources and multiple sinks. The fact that we can declare as many loggers as we want staticly or as class member gives the illusion of multiple logs, but we have really just one core log. If an application needs to log different things in separated files (different modules, different people, 3pp) we need to create two sinks, a tag dispatcher, add the corresponding filters, create to channel_loggers, and share the tag dispatcher between the different modules, people and possibly 3pp. It seem to me that this could not scale. We really need to instantiate the core log. I don't think the explicit creation of a core log and the association of source and sinks to a core will complicate the library. The library could provide in addition a singleton log, so sources and sinks will be associated to this default core log. <snip>
The single difference between synchronous_sink and asynchronous_sink is that the later will do the formating and writing later on on an other thread, isn't it? In both cases there is a mutex associated to the sink. This mutex could be the bottleneck of the system, only one mutex resource for all the user threads.
Remember that the mutex is only associated to a single sink. Writing to different sinks can be concurrent. Theoretically, the logging core can employ some clever scheduling between sinks, but this is not currently done.
As for asynchronous sink frontend, the mutex is only needed to protect the queue of records for the dedicated thread.
Yes but writing to different sources will check the filters on all the sinks. Doesn't this need to lock the mutex on the sink?
I would happily use some lock-free queue for this purpose, but Boost doesn't have one and I don't feel confident to implement one. I plan to add support for Intel TBB later.
I don't feel confident neither, at least not yet :(
Another approach for the asynchronous_sink could be to use a queue of log records for each thread (thread specific storage). Each log records must be timestamped with the creation date and a monotonic counter (time is not enough fine grained) and as the queue is specific to the thread no need to use a mutex. On the other side there is a concentrator which takes one by one the elements ordered by the timestamp+counter.
Something like that is planned in the future. However, I was going to use a single queue to interleave records during pushes.
So only the current thread can push on this queue because is specific to the thread. There is a single thread, the concentrator that pops from these queue. In this context we can ensure thread safety without locking as far as the queue has at least two messages. (The Fork/Join Java framework and Boost.ThreadPool use this technique).
You still need to synchronize pushes and pops, no matter how many queues you use. You do have two threads accessing the same queue anyway. While this will surely reduce contention, it is not lock-free.
Please take a look to the Fork/Join Java framework. The isea is that we don't need to synchronize always because the threads modifies different memory variable as far as there is more thatn two message in the queue, so it is almost lock-free in this particular context 1 writer/1 reader. I feel confident with this particular case.
There is one more issue here, because all the threads can log, while on the ThreadPool only the threads in the pool can add tasks on the queue of the worker thread. So the concentrator needs to have access to all the thread_specific storage.
The Boost.Interthreads library defines a thread_specific_shared_ptr class which extends the thread_specific_ptr class with synchronized access to thread_specific_shared_ptr of a thread from another, either giving the thread::id or iterating on a map : thread::id -> shared_ptr<stored_data>.
I have not done yet any performances comparation, but I think that the bottleneck is avoided.
Looking forward to see this library in Boost! The idea of separate queues, along with lock-free queue from TBB, looks very appealing.
You can already take a look at https://svn.boost.org/trac/boost/wiki/LibrariesUnderConstruction#Boost.Inter... or download it from the vault: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=interthreads.zip&directory=Concurrent%20Programming& The library defines an async_ostream in the deferred traces example. Note that in the example the queue are not yet lock free, I'm working on (I need to replace the std::queue by an array and two indexes).
In addition this will solve the issue with log records that are weakly ordered in a multithreaded applications.
Do you plan at least to solve the weakly ordered issue before the review?
If I have time before the review I'll try to use this approach to define an strict_asynchronous_sink which will ensure strict order and minimize the contention. Have you some performance test I can use to compare?
No, I haven't done any dedicated performance tests yet. I will try to produce something a bit later.
Locking forward to make a comparation, Vicente

Wouldn't it be better to do scoped logging ? It would prevent from mixing data when doing some MT programs, it would solve the "open_record()" problem, etc. But in this case their would be a scoped_mutex on our log writing function. And then, the destructor would log everything, so that we would be able to put many informations on the log stream and then log them all. -- Alp Mestan In charge of the C++ section on Developpez.com.

Alp Mestan wrote:
Wouldn't it be better to do scoped logging ? It would prevent from mixing data when doing some MT programs, it would solve the "open_record()" problem, etc. But in this case their would be a scoped_mutex on our log writing function. And then, the destructor would log everything, so that we would be able to put many informations on the log stream and then log them all.
Yes, that's a good idea. I have answered to Vicente on this. However, this will not solve weak record ordering in the multithreaded application, as you seem to imply. The log record does not hold any locks for performance reasons.

vicente.botet wrote:
Does it mean that the application is unable to know when things go wrong? Yes. Although extremely useful, logging is an auxiliary feature of the application, so it must not influence business logic. That is, users should not be bothered to wrap every log statement in a try/catch block.
IMO, it is up to the application to decide what to do with exceptional cases. The log library could catch its own exceptions, but not the user exceptions, and in any case let the user think that a log has been done when it is not the case.
Ok, I can make this behavior optional. Although I will most likely want to have all exceptions muted all the time.
Sources are not associated with sinks directly. A log record from any source may go to any one or several sinks. Which sinks will receive the record is entirely decided by filters.
So we can consider that sources + core + sinks form a single "log".
Sorry, I don't understand what you mean by "log". If it's a log file then it roughly corresponds to a single sink, not the whole set of objects you described.
So the BoostLog library consist of a single log with multiple sources and multiple sinks. The fact that we can declare as many loggers as we want staticly or as class member gives the illusion of multiple logs, but we have really just one core log.
I still don't understand what you mean by log. However, I don't see any illusion. You emit a log record through the logger, then it is processed according to the library set up. It may end up in one file, several or none, possibly in different form.
If an application needs to log different things in separated files (different modules, different people, 3pp) we need to create two sinks, a tag dispatcher, add the corresponding filters, create to channel_loggers, and share the tag dispatcher between the different modules, people and possibly 3pp. It seem to me that this could not scale. We really need to instantiate the core log.
There is no such thing as a "tag dispatcher" in the library. You are right, you need several sinks, each of them having a filter that will only pass records you want to see in the corresponding file (for example, records for a specific channel). That's it, the initialization stage ends here. In order to write logs you may create loggers as you need, these loggers may have different types and different attributes attached. If you want to emit a record to a particular channel, you can do so by attaching the channel name to the record as an attribute value. channel_logger does this automatically for you. Whether that channel is enabled or not, and what file it is written to, is a question of the library configuration, described earlier.
I don't think the explicit creation of a core log and the association of source and sinks to a core will complicate the library. The library could provide in addition a singleton log, so sources and sinks will be associated to this default core log.
I think, this will only confuse users. I don't see any reasonable use case where I would need to duplicate logging cores.
Yes but writing to different sources will check the filters on all the sinks. Doesn't this need to lock the mutex on the sink?
Only in read-access mode. Filters don't need serialized execution.
Looking forward to see this library in Boost! The idea of separate queues, along with lock-free queue from TBB, looks very appealing.
You can already take a look at https://svn.boost.org/trac/boost/wiki/LibrariesUnderConstruction#Boost.Inter... or download it from the vault: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=interthreads.zip&directory=Concurrent%20Programming&
Thanks for the links, I'll take a look.
In addition this will solve the issue with log records that are weakly ordered in a multithreaded applications.
Do you plan at least to solve the weakly ordered issue before the review?
AFAIK, the review version of the library must be frozen according to Boost policy. But I'm surely not planning to drop the library, so this feature may appear in CVS before the review. However, I want to finish library tests before any other feature additions.

----- Original Message ----- From: "Andrey Semashev" <andrey.semashev@gmail.com> To: <boost@lists.boost.org> Sent: Thursday, February 12, 2009 6:55 PM Subject: Re: [boost] [log] Review-ready version in the Vault
vicente.botet wrote:
Does it mean that the application is unable to know when things go wrong? Yes. Although extremely useful, logging is an auxiliary feature of the application, so it must not influence business logic. That is, users should not be bothered to wrap every log statement in a try/catch block.
IMO, it is up to the application to decide what to do with exceptional cases. The log library could catch its own exceptions, but not the user exceptions, and in any case let the user think that a log has been done when it is not the case.
Ok, I can make this behavior optional. Although I will most likely want to have all exceptions muted all the time.
I understand you position, but there are situations that need the oposit.
Sources are not associated with sinks directly. A log record from any source may go to any one or several sinks. Which sinks will receive the record is entirely decided by filters.
So we can consider that sources + core + sinks form a single "log".
Sorry, I don't understand what you mean by "log". If it's a log file then it roughly corresponds to a single sink, not the whole set of objects you described.
Well, the library is names Boost.Log isnt' it. When I talk in your library context of log I mean sources + core + sinks.
So the BoostLog library consist of a single log with multiple sources and multiple sinks. The fact that we can declare as many loggers as we want staticly or as class member gives the illusion of multiple logs, but we have really just one core log.
I still don't understand what you mean by log. However, I don't see any illusion. You emit a log record through the logger, then it is processed according to the library set up. It may end up in one file, several or none, possibly in different form.
Yes, but I can not configure several cores.
If an application needs to log different things in separated files (different modules, different people, 3pp) we need to create two sinks, a tag dispatcher, add the corresponding filters, create to channel_loggers, and share the tag dispatcher between the different modules, people and possibly 3pp. It seem to me that this could not scale. We really need to instantiate the core log.
There is no such thing as a "tag dispatcher" in the library. You are right, you need several sinks, each of them having a filter that will only pass records you want to see in the corresponding file (for example, records for a specific channel). That's it, the initialization stage ends here.
If I understand channels are identified by a string, so different 3pp will need to use a different string. With different cores each 3pp could use its own core without any trouble with other cores. What about using tags instead of strings to identify a channel?
In order to write logs you may create loggers as you need, these loggers may have different types and different attributes attached. If you want to emit a record to a particular channel, you can do so by attaching the channel name to the record as an attribute value. channel_logger does this automatically for you. Whether that channel is enabled or not, and what file it is written to, is a question of the library configuration, described earlier.
I don't think the explicit creation of a core log and the association of source and sinks to a core will complicate the library. The library could provide in addition a singleton log, so sources and sinks will be associated to this default core log.
I think, this will only confuse users. I don't see any reasonable use case where I would need to duplicate logging cores.
Let me say that I'm using two 3pp products that are using your library. They provide its own initial configuration and a backdoor to change on line the configuration. With several cores you can reach it, I don't know how you can do it with only one. Of course if your library provide only one code, I dont think 3pp library providers will use your library if they need its own configuration.
Yes but writing to different sources will check the filters on all the sinks. Doesn't this need to lock the mutex on the sink?
Only in read-access mode. Filters don't need serialized execution.
Yes, but while one thread is reading other can not write. I think your design do not scale well. With several cores, you can reduce the contention. <snip>
In addition this will solve the issue with log records that are weakly ordered in a multithreaded applications.
Do you plan at least to solve the weakly ordered issue before the review?
AFAIK, the review version of the library must be frozen according to Boost policy. But I'm surely not planning to drop the library, so this feature may appear in CVS before the review. However, I want to finish library tests before any other feature additions.
I understand. Vicente

Vicente Botet wrote:
If I understand channels are identified by a string, so different 3pp will need to use a different string. With different cores each 3pp could use its own core without any trouble with other cores. What about using tags instead of strings to identify a channel?
The channel can be identified in any way. In fact, the channel identifier is no different from any other attribute value, from the library perspective. The channel_logger provided by the library uses strings because it is the obvious and commonly used type for this purpose.
I don't think the explicit creation of a core log and the association of source and sinks to a core will complicate the library. The library could provide in addition a singleton log, so sources and sinks will be associated to this default core log.
I think, this will only confuse users. I don't see any reasonable use case where I would need to duplicate logging cores.
Let me say that I'm using two 3pp products that are using your library. They provide its own initial configuration and a backdoor to change on line the configuration. With several cores you can reach it, I don't know how you can do it with only one. Of course if your library provide only one code, I dont think 3pp library providers will use your library if they need its own configuration.
I think that a good library should support customizing the logs it produces. In your example, the third party libraries should act as log producers and support customizing their output. For instance, the libraries can expose APIs to set up their particular channel names, which will allow to split their logs into different sinks, if needed. Your application, which uses these third party libraries, should act as a configuration master and set up the sinks, filtering and formatting the way your application needs (note that it's not the way either of the libraries may impose). The application may use logging, too, but that's irrelevant to the point: it is the application who has to control logging, not the libraries.
Yes but writing to different sources will check the filters on all the sinks. Doesn't this need to lock the mutex on the sink? Only in read-access mode. Filters don't need serialized execution.
Yes, but while one thread is reading other can not write. I think your design do not scale well. With several cores, you can reduce the contention.
Like I said, acquiring the write-lock is quite rare. I'd say, typically you will only need it during the initialization phase.

Hi Andrey,
Vicente Botet wrote:
Reading the code I see a lot of
try{ // } catch (...){ // Something has gone wrong. }
Does it mean that the application is unable to know when things go wrong?
Yes. Although extremely useful, logging is an auxiliary feature of the application, so it must not influence business logic.
this statement is not true for the general case. Logging *may* be an auxiliary feature, i.e. when thinking about debug output that's of interest mostly for software developers, but there are applications that must leave a reliable audit trail, i.e. systems that deal with money and finances. For those applications, logging is part of the business logic. The same is true to some extend for applications that run in the background, like network servers, etc.
That is, users should not be bothered to wrap every log statement in a try/catch block.
However, users that do want to deal with those exceptions themselves should be able to. Take care, Peter

Peter Simons wrote:
Hi Andrey,
Vicente Botet wrote:
Reading the code I see a lot of
try{ // } catch (...){ // Something has gone wrong. }
Does it mean that the application is unable to know when things go wrong?
Yes. Although extremely useful, logging is an auxiliary feature of the application, so it must not influence business logic.
this statement is not true for the general case. Logging *may* be an auxiliary feature, i.e. when thinking about debug output that's of interest mostly for software developers, but there are applications that must leave a reliable audit trail, i.e. systems that deal with money and finances. For those applications, logging is part of the business logic. The same is true to some extend for applications that run in the background, like network servers, etc.
That is, users should not be bothered to wrap every log statement in a try/catch block.
However, users that do want to deal with those exceptions themselves should be able to.
Ok, I agree that this needs to be customizable.

vicente.botet wrote:
I have some innocent questions: * Is logging thread-safe? * If yes, are the lines interleaved as it is the case for output streams? * If not could you point out how and where in the implementation this is handled?
Hi again,
well i have found some anwers to my questions on the document. I'll come back later on.
I'm glad you did. :)
How a log record is recognized, i.e. I don't see std::endl neither std::flush are used in the examples. How many lines result in the following example if condifiton is true (2 or 3)
src::logger_mt& lg = my_logger::get(); if (lg.open_record()) { lg.strm() << "Hello "; lg.strm() << "world!"; }
That one is not valid in the current implementation. It should be replaced with: if (lg.open_record()) lg.strm() << "Hello "; if (lg.open_record()) lg.strm() << "world!"; This is because strm() returns a temporary object that confirms the opened log record on its destruction. Once confirmed, the record is dispatched and cannot be modified, so a new record must be opened.
// do something if (condition) { if (lg.open_record()) lg.strm() << "Bye!"; }
Every complete streaming statement is a log record. So, you emit three records in your code sample, assuming that all conditions are true and the needed corrections are made.
Can other logs be interleaved between "Hello " , "world!" and Bye in a multi threaded program?
Yes.

On 11 Feb 2009, at 19:28, Andrey Semashev wrote:
vicente.botet wrote:
I have some innocent questions: * Is logging thread-safe? * If yes, are the lines interleaved as it is the case for output streams? * If not could you point out how and where in the implementation this is handled? Hi again, well i have found some anwers to my questions on the document. I'll come back later on.
I'm glad you did. :)
How a log record is recognized, i.e. I don't see std::endl neither std::flush are used in the examples. How many lines result in the following example if condifiton is true (2 or 3) src::logger_mt& lg = my_logger::get(); if (lg.open_record()) { lg.strm() << "Hello "; lg.strm() << "world!"; }
That one is not valid in the current implementation. It should be replaced with:
if (lg.open_record()) lg.strm() << "Hello "; if (lg.open_record()) lg.strm() << "world!";
What would happen if someone did write the above? I really don't think this is an acceptable limitation. Don't you think people will often write to a stream more than once in the same function? Chris

Christopher Jefferson wrote:
On 11 Feb 2009, at 19:28, Andrey Semashev wrote:
vicente.botet wrote:
I have some innocent questions: * Is logging thread-safe? * If yes, are the lines interleaved as it is the case for output streams? * If not could you point out how and where in the implementation this is handled? Hi again, well i have found some anwers to my questions on the document. I'll come back later on.
I'm glad you did. :)
How a log record is recognized, i.e. I don't see std::endl neither std::flush are used in the examples. How many lines result in the following example if condifiton is true (2 or 3) src::logger_mt& lg = my_logger::get(); if (lg.open_record()) { lg.strm() << "Hello "; lg.strm() << "world!"; }
That one is not valid in the current implementation. It should be replaced with:
if (lg.open_record()) lg.strm() << "Hello "; if (lg.open_record()) lg.strm() << "world!";
What would happen if someone did write the above?
Officially - unspecified behavior. In current implementation, in case if no records are open recursively, the library would open a new record itself.
I really don't think this is an acceptable limitation. Don't you think people will often write to a stream more than once in the same function?
No, I think they won't. Most of the time BOOST_LOG & co. macros will be used, and they hide this "if" internally: BOOST_LOG(lg) << "Hello";

----- Original Message ----- From: "Andrey Semashev" <andrey.semashev@gmail.com> To: <boost@lists.boost.org> Sent: Wednesday, February 11, 2009 10:01 PM Subject: Re: [boost] [log] Review-ready version in the Vault
Christopher Jefferson wrote:
On 11 Feb 2009, at 19:28, Andrey Semashev wrote:
vicente.botet wrote:
I have some innocent questions: * Is logging thread-safe? * If yes, are the lines interleaved as it is the case for output streams? * If not could you point out how and where in the implementation this is handled? Hi again, well i have found some anwers to my questions on the document. I'll come back later on.
I'm glad you did. :)
How a log record is recognized, i.e. I don't see std::endl neither std::flush are used in the examples. How many lines result in the following example if condifiton is true (2 or 3) src::logger_mt& lg = my_logger::get(); if (lg.open_record()) { lg.strm() << "Hello "; lg.strm() << "world!"; }
You have not answered my question. Anyway, looking on the code I've found that the log record delimiter is the destructor of the record_pump_type record_pump_type strm(); So when we write lg.strm() << "Hello "; we have a record.
That one is not valid in the current implementation. It should be replaced with:
if (lg.open_record()) lg.strm() << "Hello "; if (lg.open_record()) lg.strm() << "world!";
What would happen if someone did write the above?
Officially - unspecified behavior. In current implementation, in case if no records are open recursively, the library would open a new record itself.
Unacceptable IMHO. The user don't need to check if logs are enabled. I don't like that bool open_record(); open a record and check if the logging is enabled and the record is closed only when a temporary record_pump_type is destroyed. Why not have 3 functions enabled, open_record and close_record, and why not have a scoped_record? Well the open_record will be not needed if we have always a record opened (i.e. a new record is opened implicitly after a close_record.
I really don't think this is an acceptable limitation. Don't you think people will often write to a stream more than once in the same function?
No, I think they won't. Most of the time BOOST_LOG & co. macros will be used, and they hide this "if" internally:
BOOST_LOG(lg) << "Hello";
Sorry, but people has a lot of different needs. When the log library use the << operator, he must mimic the standard STL. The user needs to master the log record delimiter in some way. Some times we need to use some conditions and loops to prepare the log record. We can found code like the following : if (traces_enabled) { for (it=begin;it!end; ++it) { std::cout << *it ; if (it+1!=end) std::cout << ", "; else std::cout << std::endl; } } So when I move to the logging library I would like to do something like. if (lg.enabled()) { for (it=begin;it!end; ++it) { lg.strm() << *it ; if (it+1!=end) lg.strm() << ", "; else lg.strm() << std::endl; } } But you force to create a temporary string stream which is in contradiction with your principles,i.e. not simple neither efficient. if (lg.open_record()) { string_stream strm; for (it=begin;it!end; ++it) { strm << *it ; if (it+1!=end) strm << ", "; } lg.strm() << strm.str(); } What do you think about this if (lg.enabled()) { for (it=begin;it!end; ++it) { lg << *it ; if (it+1!=end) lg << ", "; else lg << std::endl; } } std::endl will close the record. Or with a scoped log record if (lg.enabled()) { scoped_log_record rec(lg); for (it=begin;it!end; ++it) { rec << *it ; if (it+1!=end) rec << ", "; } } Best, Vicente

vicente.botet wrote:
You have not answered my question.
Actually, I did write in my reply to you nearly the same that you've discovered. Doesn't matter, though.
That one is not valid in the current implementation. It should be replaced with:
if (lg.open_record()) lg.strm() << "Hello "; if (lg.open_record()) lg.strm() << "world!"; What would happen if someone did write the above? Officially - unspecified behavior. In current implementation, in case if no records are open recursively, the library would open a new record itself.
Unacceptable IMHO. The user don't need to check if logs are enabled.
He does need to open a record in some way. Opening a record is not only filtering, although this is a part of the process. The key point of opening a record is acquiring values of all attributes and composing them into a single view. It is this view then processed by filters, formatters and sinks.
I don't like that bool open_record(); open a record and check if the logging is enabled and the record is closed only when a temporary record_pump_type is destroyed.
Why not have 3 functions enabled, open_record and close_record, and why not have a scoped_record?
For the reason I've described above. "enabled" will have to implicitly call "open_record".
and why not have a scoped_record?
That's another question. The main background behind the current design decision is that the scoped_record object introduces a danger of misuse. For example, one could attempt to pass it to another thread or store in a container. On the other hand, I realize that the current interface is not perfect, too, so I have no strong position. FWIW, it should be quite simple to change this.
Well the open_record will be not needed if we have always a record opened (i.e. a new record is opened implicitly after a close_record.
That is not possible for several reasons: * To construct the attribute values view the set of the source-specific attributes is needed * This view will not be able to reflect changes to the attribute sets * This introduces problems in case of recursive logging. E.g.: int foo() { BOOST_LOG(lg) << "hello"; } BOOST_LOG(lg) << foo();
I really don't think this is an acceptable limitation. Don't you think people will often write to a stream more than once in the same function? No, I think they won't. Most of the time BOOST_LOG & co. macros will be used, and they hide this "if" internally:
BOOST_LOG(lg) << "Hello";
Sorry, but people has a lot of different needs. When the log library use the << operator, he must mimic the standard STL. The user needs to master the log record delimiter in some way. Some times we need to use some conditions and loops to prepare the log record. We can found code like the following :
[snip] All these cases are covered by stream manipulators and operator<< overriding. I must say, this approach is much more appealing than writing inline loops etc., since it may be reused regardless of logging.
What do you think about this if (lg.enabled()) { for (it=begin;it!end; ++it) { lg << *it ; if (it+1!=end) lg << ", "; else lg << std::endl; } }
std::endl will close the record.
I would really dislike to override behavior of the standard manipulators. And introducing a special manipulator doesn't seem reasonable to me.
Or with a scoped log record if (lg.enabled()) { scoped_log_record rec(lg); for (it=begin;it!end; ++it) { rec << *it ; if (it+1!=end) rec << ", "; } }
That looks much more attractive. However, I had something like this in mind: if (log_record rec = lg.open_record()) { rec.strm() << ...; } The one problem I see here is how to deduce the log_record type from lg. I don't want to use Boost.TypeOf since it looks too heavy to me.

Steven Watanabe wrote:
AMDG
Andrey Semashev wrote:
I don't want to use Boost.TypeOf since it looks too heavy to me.
Only for compilers without built in typeof support.
I know only GCC of such. MSVC is supported through some compiler-specific trick, AFAIK. It doesn't look like a widely adopted feature nowdays.

----- Original Message ----- From: "Andrey Semashev" <andrey.semashev@gmail.com> To: <boost@lists.boost.org> Sent: Thursday, February 12, 2009 5:55 PM Subject: Re: [boost] [log] Review-ready version in the Vault
vicente.botet wrote:
That one is not valid in the current implementation. It should be replaced with:
if (lg.open_record()) lg.strm() << "Hello "; if (lg.open_record()) lg.strm() << "world!"; What would happen if someone did write the above? Officially - unspecified behavior. In current implementation, in case if no records are open recursively, the library would open a new record itself.
Unacceptable IMHO. The user don't need to check if logs are enabled.
He does need to open a record in some way. Opening a record is not only filtering, although this is a part of the process. The key point of opening a record is acquiring values of all attributes and composing them into a single view. It is this view then processed by filters, formatters and sinks.
I have no problem with opening the log record, the problem is that you close the record as soon as the destructor on the remporary is called. Anyway, this is an implementation detail. Checking should be be able to be done without a log record opened.
I don't like that bool open_record(); open a record and check if the logging is enabled and the record is closed only when a temporary record_pump_type is destroyed.
Why not have 3 functions enabled, open_record and close_record, and why not have a scoped_record?
For the reason I've described above. "enabled" will have to implicitly call "open_record".
I desagree in this pooint.
and why not have a scoped_record?
That's another question. The main background behind the current design decision is that the scoped_record object introduces a danger of misuse. For example, one could attempt to pass it to another thread or store in a container.
Well, you can delete the operator&, copy constructor, copy assignement, ...
On the other hand, I realize that the current interface is not perfect, too, so I have no strong position. FWIW, it should be quite simple to change this.
I'm sure that this will not be complicated. But this can not be made from outside, so I need you change it.
Well the open_record will be not needed if we have always a record opened (i.e. a new record is opened implicitly after a close_record.
That is not possible for several reasons: * To construct the attribute values view the set of the source-specific attributes is needed * This view will not be able to reflect changes to the attribute sets * This introduces problems in case of recursive logging. E.g.:
int foo() { BOOST_LOG(lg) << "hello"; }
BOOST_LOG(lg) << foo();
Ok, I see.
I really don't think this is an acceptable limitation. Don't you think people will often write to a stream more than once in the same function? No, I think they won't. Most of the time BOOST_LOG & co. macros will be used, and they hide this "if" internally:
BOOST_LOG(lg) << "Hello";
Sorry, but people has a lot of different needs. When the log library use the << operator, he must mimic the standard STL. The user needs to master the log record delimiter in some way. Some times we need to use some conditions and loops to prepare the log record. We can found code like the following :
[snip]
All these cases are covered by stream manipulators and operator<< overriding. I must say, this approach is much more appealing than writing inline loops etc., since it may be reused regardless of logging.
This was just an example. You will need to inline loops on the operator<< overriding, isn't it?
What do you think about this if (lg.enabled()) { for (it=begin;it!end; ++it) { lg << *it ; if (it+1!=end) lg << ", "; else lg << std::endl; } }
std::endl will close the record.
I would really dislike to override behavior of the standard manipulators.
Why? Is there a deep reason?
And introducing a special manipulator doesn't seem reasonable to me.
Neither to me.
Or with a scoped log record if (lg.enabled()) { scoped_log_record rec(lg); for (it=begin;it!end; ++it) { rec << *it ; if (it+1!=end) rec << ", "; } }
That looks much more attractive. However, I had something like this in mind:
if (log_record rec = lg.open_record()) { rec.strm() << ...; }
The one problem I see here is how to deduce the log_record type from lg. I don't want to use Boost.TypeOf since it looks too heavy to me.
What about defining it inside the logger? logger_type lg; if (logger_type::scoped_log_record rec = lg.open_record()) { rec.strm() << ...; } Why do you need to get the strm to be able to log? Why not just rec << ...; Best, Vicente

vicente.botet wrote:
Unacceptable IMHO. The user don't need to check if logs are enabled. He does need to open a record in some way. Opening a record is not only filtering, although this is a part of the process. The key point of opening a record is acquiring values of all attributes and composing them into a single view. It is this view then processed by filters, formatters and sinks.
I have no problem with opening the log record, the problem is that you close the record as soon as the destructor on the remporary is called.
Anyway, this is an implementation detail. Checking should be be able to be done without a log record opened.
Why not have 3 functions enabled, open_record and close_record, and why not have a scoped_record? For the reason I've described above. "enabled" will have to implicitly call "open_record".
I desagree in this pooint.
You cannot execute the filter without having a view of attribute values because the filter makes its decision based on this view. Do you have something different on your mind?
On the other hand, I realize that the current interface is not perfect, too, so I have no strong position. FWIW, it should be quite simple to change this.
I'm sure that this will not be complicated. But this can not be made from outside, so I need you change it.
Ok, I'll do so.
[snip]
All these cases are covered by stream manipulators and operator<< overriding. I must say, this approach is much more appealing than writing inline loops etc., since it may be reused regardless of logging.
This was just an example. You will need to inline loops on the operator<< overriding, isn't it?
Yes, but these manipulators or operator<< overloads can be reused.
What do you think about this if (lg.enabled()) { for (it=begin;it!end; ++it) { lg << *it ; if (it+1!=end) lg << ", "; else lg << std::endl; } }
std::endl will close the record. I would really dislike to override behavior of the standard manipulators.
Why? Is there a deep reason?
The left-hand argument of operator<< is an std::basic_ostream, which handles these manipulators itself. So, the only way to detect the manipulator in action is to observe its effects in the stream buffer. In case of std::endl this would mean searching the formatted data for '\n', which is a performance loss and is not valid in general (since a log record can contain several lines of text). I think that scoped records are the way to go.
That looks much more attractive. However, I had something like this in mind:
if (log_record rec = lg.open_record()) { rec.strm() << ...; }
The one problem I see here is how to deduce the log_record type from lg. I don't want to use Boost.TypeOf since it looks too heavy to me.
What about defining it inside the logger?
logger_type lg; if (logger_type::scoped_log_record rec = lg.open_record()) { rec.strm() << ...; }
The problem is that I don't have logger_type in the BOOST_LOG(lg) macro.
Why do you need to get the strm to be able to log? Why not just
rec << ...;
I can do that.

----- Original Message ----- From: "Andrey Semashev" <andrey.semashev@gmail.com> To: <boost@lists.boost.org> Sent: Thursday, February 12, 2009 7:12 PM Subject: Re: [boost] [log] Review-ready version in the Vault
vicente.botet wrote:
Unacceptable IMHO. The user don't need to check if logs are enabled. He does need to open a record in some way. Opening a record is not only filtering, although this is a part of the process. The key point of opening a record is acquiring values of all attributes and composing them into a single view. It is this view then processed by filters, formatters and sinks.
I have no problem with opening the log record, the problem is that you close the record as soon as the destructor on the remporary is called.
Anyway, this is an implementation detail. Checking should be be able to be done without a log record opened.
Why not have 3 functions enabled, open_record and close_record, and why not have a scoped_record? For the reason I've described above. "enabled" will have to implicitly call "open_record".
I desagree in this pooint.
You cannot execute the filter without having a view of attribute values because the filter makes its decision based on this view. Do you have something different on your mind?
Why not making the filter just in a view of attributes values, not the record itself. If I have understood, the library do not proposse firter on log records.
On the other hand, I realize that the current interface is not perfect, too, so I have no strong position. FWIW, it should be quite simple to change this.
I'm sure that this will not be complicated. But this can not be made from outside, so I need you change it.
Ok, I'll do so.
Thanks :)
[snip]
All these cases are covered by stream manipulators and operator<< overriding. I must say, this approach is much more appealing than writing inline loops etc., since it may be reused regardless of logging.
This was just an example. You will need to inline loops on the operator<< overriding, isn't it?
Yes, but these manipulators or operator<< overloads can be reused.
Sorry, I don't undesrtand. Could you elaborate on that.
What do you think about this if (lg.enabled()) { for (it=begin;it!end; ++it) { lg << *it ; if (it+1!=end) lg << ", "; else lg << std::endl; } }
std::endl will close the record. I would really dislike to override behavior of the standard manipulators.
Why? Is there a deep reason?
The left-hand argument of operator<< is an std::basic_ostream, which handles these manipulators itself. So, the only way to detect the manipulator in action is to observe its effects in the stream buffer. In case of std::endl this would mean searching the formatted data for '\n', which is a performance loss and is not valid in general (since a log record can contain several lines of text).
I was not talking of \n record separator, but std::endl which is a \n + flush. In My opinion, is the flush operation which should pust the record. Well you can make a wrapper with the IoStream library, and should be able to redefine the flush operation.
I think that scoped records are the way to go.
Maybe.
That looks much more attractive. However, I had something like this in mind:
if (log_record rec = lg.open_record()) { rec.strm() << ...; }
The one problem I see here is how to deduce the log_record type from lg. I don't want to use Boost.TypeOf since it looks too heavy to me.
What about defining it inside the logger?
logger_type lg; if (logger_type::scoped_log_record rec = lg.open_record()) { rec.strm() << ...; }
The problem is that I don't have logger_type in the BOOST_LOG(lg) macro.
The BOOST_LOG macro is another issue. When you use the BOOST_LOG you can state this macro push a log record, and maybe you will need to use the current interface. My concern is that the application must be able to master the log record delimiter, not that this must be done on the macro.
Why do you need to get the strm to be able to log? Why not just
rec << ...;
I can do that.
It will be clearer. Thanks for all your answers, Vicente

vicente.botet wrote:
He does need to open a record in some way. Opening a record is not only filtering, although this is a part of the process. The key point of opening a record is acquiring values of all attributes and composing them into a single view. It is this view then processed by filters, formatters and sinks.
I desagree in this pooint.
You cannot execute the filter without having a view of attribute values because the filter makes its decision based on this view. Do you have something different on your mind?
Why not making the filter just in a view of attributes values, not the record itself. If I have understood, the library do not proposse firter on log records.
I'm sorry, you're losing me here. Could you rephrase your suggestion, please? A pseudo-code snippet would be helpful.
All these cases are covered by stream manipulators and operator<< overriding. I must say, this approach is much more appealing than writing inline loops etc., since it may be reused regardless of logging. This was just an example. You will need to inline loops on the operator<< overriding, isn't it? Yes, but these manipulators or operator<< overloads can be reused.
Sorry, I don't undesrtand. Could you elaborate on that.
You could have something like this: template< typename RangeT > struct range_manip_t { RangeT& range_; template< typename CharT > friend std::basic_ostream< CharT >& operator<< ( std::basic_ostream< CharT >& strm, range_manip_t const& r) { std::for_each( begin(r.range_), end(r.range_), var(strm) << _1); return strm; } }; template< typename RangeT > range_manip_t< RangeT > range_manip(RangeT& r) { return range_manip_t< RangeT >(r); } Now you can use it with any ranges and streams, including logs. std::list< int > l; std::vector< std::string > v; boost::iterator_range< double* > r; std::cout << range_manip(l); std::wostringstream wss; wss << range_manip(v); BOOST_LOG(lg) << range_manip(r);
That looks much more attractive. However, I had something like this in mind:
if (log_record rec = lg.open_record()) { rec.strm() << ...; }
The one problem I see here is how to deduce the log_record type from lg. I don't want to use Boost.TypeOf since it looks too heavy to me. What about defining it inside the logger?
logger_type lg; if (logger_type::scoped_log_record rec = lg.open_record()) { rec.strm() << ...; } The problem is that I don't have logger_type in the BOOST_LOG(lg) macro.
The BOOST_LOG macro is another issue. When you use the BOOST_LOG you can state this macro push a log record, and maybe you will need to use the current interface. My concern is that the application must be able to master the log record delimiter, not that this must be done on the macro.
Well, I'd like the library interface to be as consistent as possible. I'll have to think more on this.

vicente.botet wrote:
Hi, I have just started to read the documentation, and it is not easy to make the distinction between a elements in the library and the others. Can I suggest to rename the namesapce alias? Instead of
namespace logging = boost::log; namespace sinks = boost::log::sinks; namespace src = boost::log::sources; namespace fmt = boost::log::formatters; namespace flt = boost::log::filters; namespace attrs = boost::log::attributes;
use namespace blog = boost::log; namespace blsinks = boost::log::sinks; namespace blsrc = boost::log::sources; namespace blfmt = boost::log::formatters; namespace blflt = boost::log::filters; namespace blattrs = boost::log::attributes;
So every thing starting with bl is an element of the library.
Hmm... Don't you think that it mangles the aliases too much?

Hi Andrey, the latest version of the library compiled fine on Linux and Windows, and it also succeeded all regression tests. Thank you for your efforts. Now that I have actually experimented with the code, I realize that there is no portable implementation of syslog(3), i.e. your library cannot submit log entries to syslog from non-POSIX platforms, like Windows. Maybe I am missing something terribly obvious? Anyway, the ability to access syslog is important to me, but I don't have the time to implement an appropriate sink myself. So, if there is some sort of wish-list for things that will be added, I'd be very happy to see this particular feature on that wish-list. I suspect some other people who work primarily with heterogeneous networks will share that sentiment. Take care, Peter

Peter Simons wrote:
Now that I have actually experimented with the code, I realize that there is no portable implementation of syslog(3), i.e. your library cannot submit log entries to syslog from non-POSIX platforms, like Windows. Maybe I am missing something terribly obvious?
Yes, the syslog sink uses native API to write logs. I'm not aware of any syslog client API implemented for Windows, so this sink is not available on this platform.
Anyway, the ability to access syslog is important to me, but I don't have the time to implement an appropriate sink myself. So, if there is some sort of wish-list for things that will be added, I'd be very happy to see this particular feature on that wish-list. I suspect some other people who work primarily with heterogeneous networks will share that sentiment.
I totally agree that lack of syslog client on Windows is a huge gap. However, I believe such a project should be standalone, and probably outside of Boost. Maybe, if I have enough time, I will start one.

Hi Andrey,
I totally agree that lack of [syslog support] on Windows is a huge gap. However, I believe such a project should be standalone, and probably outside of Boost.
in my humble opinion, platform-independence is one of the key benefits that I'd expect from using a library such as Boost.Log. If your library doesn't provide that, then I would not want to see it included in Boost. Just my 2 cents, Peter

On Thursday 12 February 2009 07:30:26 Peter Simons wrote:
I totally agree that lack of [syslog support] on Windows is a huge gap. However, I believe such a project should be standalone, and probably outside of Boost.
in my humble opinion, platform-independence is one of the key benefits that I'd expect from using a library such as Boost.Log. If your library doesn't provide that, then I would not want to see it included in Boost.
Such an approach would mean that *every feature* available from a boost library would be required to work with all platforms. That is simply not possible. All it would lead to, IMHO, is that featrues supported only on a subset of platforms would be relegated to an "examples" directory which is unlikely to be tested as well as the core code would be. In this particular case, syslog support is simply lagniappe from a library that solves a whole host of other issues; no other part of the library depends on syslog support. Why would the presence of something extra (which does not work on only one platform) invalidate the presence of the entire library? Regards, Ravi

Hi Ravi,
in my humble opinion, platform-independence is one of the key benefits that I'd expect from using a library such as Boost.Log. If your library doesn't provide that, then I would not want to see it included in Boost.
Such an approach would mean that *every feature* available from a boost library would be required to work with all platforms.
I beg to differ. I didn't say anything about "every feature" available from "every boost library". I was talking purely about syslog support in Boost.Log. In my humble opinion, the ability to submit log messages to syslog is important. If the proposed logging library can't do that, then the library is not particularly useful to me. Other people have different expectations, so they'll feel differently about this subject.
In this particular case, syslog support is simply lagniappe from a library that solves a whole host of other issues [...].
Apparently you and I have different expectations. For me, all these other issues are just lagniappe. I don't care much about funky message formatters, attribute systems, and run-time configurable filters. I don't need any of that. However, I do need the ability to submit log messages to an RFC 3164 conforming syslog daemon. Just my 2 cents, Peter

On Thu, 12 Feb 2009 16:09:15 +0100, Peter Simons <simons@cryp.to> wrote:
[...] > In this particular case, syslog support is simply lagniappe from a
library that solves a whole host of other issues [...].
Apparently you and I have different expectations. For me, all these other issues are just lagniappe. I don't care much about funky message formatters, attribute systems, and run-time configurable filters. I don't need any of that. However, I do need the ability to submit log messages to an RFC 3164 conforming syslog daemon.
I'm as puzzled as Ravi. Do I understand correctly that you expect a Boost library to make a platform-specific feature platform-independent? Boris

Hi Boris,
I need the ability to submit log messages to an RFC 3164 conforming syslog daemon.
I'm as puzzled as Ravi. Do I understand correctly that you expect a Boost library to make a platform-specific feature platform-independent?
yes, you understood me correctly. Why does that notion puzzle you? There are plenty of Boost libraries that abstract platform-specific features underneath a platform-independent API, i.e. Boost.Asio, Boost.Thread, Boost.Filesystem, Boost.Interprocess, and so on. It is quite common for libraries to do that. Anyway, there seems to be a misunderstanding. The protocol specified in RFC3164 is platform-independent. It just so happens that the proposed logging library doesn't implement that protocol. Instead, it relies on the POSIX call syslog(3), which is not available on platforms like Windows. Thus, the syslog back-end in the proposed logging library is platform-specific even though the functionality itself is not. Personally, I perceive that as an unnecessary limitation that should be lifted. However, Andrey has stated that he doesn't want to remedy that limitation as part of his proposal, which is why I am unhappy about the proposed library. Take care, Peter

Peter Simons wrote:
Hi Boris,
I need the ability to submit log messages to an RFC 3164 conforming syslog daemon.
I'm as puzzled as Ravi. Do I understand correctly that you expect a Boost library to make a platform-specific feature platform-independent?
yes, you understood me correctly. Why does that notion puzzle you? There are plenty of Boost libraries that abstract platform-specific features underneath a platform-independent API, i.e. Boost.Asio, Boost.Thread, Boost.Filesystem, Boost.Interprocess, and so on. It is quite common for libraries to do that.
These libraries use the respective native APIs to provide their portable interface. AFAIK, none of them tries to reimplement these APIs on platforms that don't support it. And as for Filesystem, since you mentioned, it is going to drop the Cygwin platform because it doesn't provide the needed support for wide strings.

Anyway, there seems to be a misunderstanding. The protocol specified in RFC3164 is platform-independent. It just so happens that the proposed logging library doesn't implement that protocol. Instead, it relies on the POSIX call syslog(3), which is not available on platforms like Windows. Thus, the syslog back-end in the proposed logging library is platform-specific even though the functionality itself is not. Personally, I perceive that as an unnecessary limitation that should be lifted. However, Andrey has stated that he doesn't want to remedy that limitation as part of his proposal, which is why I am unhappy about the proposed library.
If it is so important for you,then I think that Andrey is happy if you would provide an implementation. I think it is not important that every sink is implemented on every platform... Regards

Peter Simons wrote:
Hi Boris,
I need the ability to submit log messages to an RFC 3164 conforming syslog daemon.
I'm as puzzled as Ravi. Do I understand correctly that you expect a Boost library to make a platform-specific feature platform-independent?
yes, you understood me correctly. Why does that notion puzzle you? There are plenty of Boost libraries that abstract platform-specific features underneath a platform-independent API, i.e. Boost.Asio, Boost.Thread, Boost.Filesystem, Boost.Interprocess, and so on. It is quite common for libraries to do that.
Anyway, there seems to be a misunderstanding. The protocol specified in RFC3164 is platform-independent. It just so happens that the proposed logging library doesn't implement that protocol. Instead, it relies on the POSIX call syslog(3), which is not available on platforms like Windows. Thus, the syslog back-end in the proposed logging library is platform-specific even though the functionality itself is not. Personally, I perceive that as an unnecessary limitation that should be lifted. However, Andrey has stated that he doesn't want to remedy that limitation as part of his proposal, which is why I am unhappy about the proposed library.
Take care, Peter
syslog() generates log messages for syslogd. There is no syslogd on windows. Where do you expect the syslog backend pass the messages to? BR, Dmitry

On Fri, 13 Feb 2009 11:35:05 +0300, Dmitry Goncharov <dgoncharov@unison.com> wrote:
syslog() generates log messages for syslogd. There is no syslogd on windows. Where do you expect the syslog backend pass the messages to?
There is an event journal in Windows, messages could end in the applications category. -- EA

Edouard A. schrieb:
On Fri, 13 Feb 2009 11:35:05 +0300, Dmitry Goncharov <dgoncharov@unison.com> wrote:
syslog() generates log messages for syslogd. There is no syslogd on windows. Where do you expect the syslog backend pass the messages to?
There is an event journal in Windows, messages could end in the applications category.
If you want that the messages are in the event journal than I think that you shoul use a sink which sends the messages there. This journal has nothing to do with a syslog backend....

On Fri, 13 Feb 2009 09:53:47 +0100, Hansi <hansipet@web.de> wrote:
If you want that the messages are in the event journal than I think that you shoul use a sink which sends the messages there. This journal has nothing to do with a syslog backend....
I don't know what the implementations details would be, I was just pointing out a close equivalent of syslogd in Windows. -- EA

Edouard A. schrieb:
On Fri, 13 Feb 2009 09:53:47 +0100, Hansi <hansipet@web.de> wrote:
If you want that the messages are in the event journal than I think that you shoul use a sink which sends the messages there. This journal has nothing to do with a syslog backend....
I don't know what the implementations details would be, I was just pointing out a close equivalent of syslogd in Windows.
see http://boost-log.sourceforge.net/libs/log/doc/html/advanced/advanced/sink_ba... This backend exists already...

On Fri, 13 Feb 2009 10:06:27 +0100, Hansi <hansipet@web.de> wrote:
see
http://boost-log.sourceforge.net/libs/log/doc/html/advanced/advanced/sink_ba... I'm really sorry, I missed that. If I select a non existing category, like, "MyApplication", will the sink create it for me? Can I log to a different computer than localhost? I cannot find any reference about this in the documentation. -- EA

Edouard A. wrote:
If I select a non existing category, like, "MyApplication", will the sink create it for me?
Not sure what exactly you mean, but no, I don't think so. Event categories are defined in the .mc file and they are compiled into a binary resource, which is then utilized by the Event Viewer. This resource cannot be modified, other than by recompiling it. If events that are emitted by the sink contain some non-existent category, I guess, the Event Viewer will show them as errors. The event description will still be visible, though.
Can I log to a different computer than localhost?
No, not yet. That can be easily added, if I'm not missing anything.

Not sure what exactly you mean, but no, I don't think so. Event categories are defined in the .mc file and they are compiled into a binary resource, which is then utilized by the Event Viewer. This resource cannot be modified, other than by recompiling it.
In the call to RegisterEventSource, you specify a source. My question is how do you handle non existing source? Do you create it? Do you let the default behavior occur (log to application)? Do you throw an exception? To create an event source you need to create a key in the registry and then set appropriate rights to make sure that it cannot be modified by unauthorized users/processes. There is a potential security issue here. If an external process creates the source before you do it, it will get all rights and possibly will remove entries (or add ones, but generally you want to remove/modify entries) as it may see fit. Sometimes the malicious application purpose is only log duplication. Therefore, you need to have clear behavior when creating the log source so that when you use the sink you know what to expect. What you can do is have a different call to create the source and throw an exception when the source doesn't exist. One may note that this security issue is not specific to the event viewer, that's also true when logging to files.
If events that are emitted by the sink contain some non-existent category, I guess, the Event Viewer will show them as errors. The event description will still be visible, though.
Can I log to a different computer than localhost?
No, not yet. That can be easily added, if I'm not missing anything.
That's very interesting for distributed computing where centralizing logging makes a lot of sense. It's very straightforward, you just have to specify the name of the server (UNC format) in the call to RegisterEventSource. Kind regards. -- Edouard Alligand

Edouard A. wrote:
Not sure what exactly you mean, but no, I don't think so. Event categories are defined in the .mc file and they are compiled into a binary resource, which is then utilized by the Event Viewer. This resource cannot be modified, other than by recompiling it.
In the call to RegisterEventSource, you specify a source. My question is how do you handle non existing source? Do you create it? Do you let the default behavior occur (log to application)? Do you throw an exception?
AFAIT from MSDN, this API will silently use the Application log source, if the specified source is not found in the registry. The sink reflects that behavior.
To create an event source you need to create a key in the registry and then set appropriate rights to make sure that it cannot be modified by unauthorized users/processes.
There is a potential security issue here. If an external process creates the source before you do it, it will get all rights and possibly will remove entries (or add ones, but generally you want to remove/modify entries) as it may see fit. Sometimes the malicious application purpose is only log duplication.
Therefore, you need to have clear behavior when creating the log source so that when you use the sink you know what to expect. What you can do is have a different call to create the source and throw an exception when the source doesn't exist.
The source registration can be done either on-demand or forced. In the first case, if the source is already registered, the sink backend doesn't modify its registry entries. This mode can be useful if the source is already registered by, say, installer. In the forced mode the sink will overwrite the registration even if it's already present in the registry. In any case, if the source registration fails, you will have an exception. I believe, this option allows to detect such security problems.
Can I log to a different computer than localhost? No, not yet. That can be easily added, if I'm not missing anything.
That's very interesting for distributed computing where centralizing logging makes a lot of sense.
It's very straightforward, you just have to specify the name of the server (UNC format) in the call to RegisterEventSource.
That's true. I will add it.

Dmitry Goncharov wrote:
syslog() generates log messages for syslogd. There is no syslogd on windows. Where do you expect the syslog backend pass the messages to?
The syslog() and syslogd are the POSIX API, which among other things allows to send log data to a remote server, using the syslog protocol, which Peter refers to as RFC3164. The syslogd daemon, as well as many other similar daemons, is capable of doing many more things with the log data than to send it via the syslog protocol. I feel that this approach may be valid for Windows, too. In particular, I think that implementing a POSIX-compliant syslog API can have its independent value. Among traditional support for RFC3164 and log files it could support Windows-specific actions, like passing log records to the Windows Event Log. As for Boost.Log, once the POSIX API is implemented on Windows, it will be supported by Boost.Log right away.

----- Original Message ----- From: "Andrey Semashev" <andrey.semashev@gmail.com> To: <boost@lists.boost.org> Sent: Friday, February 13, 2009 4:15 PM Subject: Re: [boost] [log] Review-ready version in the Vault
Dmitry Goncharov wrote:
syslog() generates log messages for syslogd. There is no syslogd on windows. Where do you expect the syslog backend pass the messages to?
The syslog() and syslogd are the POSIX API, which among other things allows to send log data to a remote server, using the syslog protocol, which Peter refers to as RFC3164. The syslogd daemon, as well as many other similar daemons, is capable of doing many more things with the log data than to send it via the syslog protocol.
I feel that this approach may be valid for Windows, too. In particular, I think that implementing a POSIX-compliant syslog API can have its independent value. Among traditional support for RFC3164 and log files it could support Windows-specific actions, like passing log records to the Windows Event Log.
As for Boost.Log, once the POSIX API is implemented on Windows, it will be supported by Boost.Log right away.
I agree, it is not the responsability of Boost.Log to provide a a POSIX-compliant syslog API implementation on every platform, in particular on Windows. Vicente

On Fri, 2009-02-13 at 18:12 +0100, vicente.botet wrote:
Dmitry Goncharov wrote:
syslog() generates log messages for syslogd. There is no syslogd on windows. Where do you expect the syslog backend pass the messages to?
The syslog() and syslogd are the POSIX API, which among other things allows to send log data to a remote server, using the syslog protocol, which Peter refers to as RFC3164.
RFC3164, titled "The (BSD) Syslog Protocol" defines a protocol. Quite a number of implementations of "a syslog protocol" bearing a close resemblance to the protocol described in RFC3164 existed well before RFC3164 was written. RFC3164's purpose is to provide a specification for an interoperable, cross platform way of sending log messages, implementable on the widest variety of platforms possible (essentially, any platform that can send UDP datagrams). It explicitly does not cover what the reciever of those log messages does with them. The receiver would, conventionally, be sylogd, but RFC3164 does not require that.
The syslogd daemon, as well as many other similar daemons, is capable of doing many more things with the log data than to send it via the syslog protocol.
Precisely. I see a whole lot of people saying that logging should not include a syslog daemon implementation - which seems to be a consensus view - I haven't seen anyone ask for one???
I feel that this approach may be valid for Windows, too. In particular, I think that implementing a POSIX-compliant syslog API can have its independent value. Among traditional support for RFC3164 and log files it could support Windows-specific actions, like passing log records to the Windows Event Log.
This syslogd on wondows project is all very well, but has nothing to do with boost log as proposed. It also has nothing to do with RFC3164 (beyond the fact that such a syslogd would need to include RFC3164 receiver capability).
As for Boost.Log, once the POSIX API is implemented on Windows, it will be supported by Boost.Log right away.
What exactly do you mean by the vague reference to the "posix syslog API"? Windows (if you install SFU) has a posix API and guess what - it includes a syslogd. Similarly, you can run cygwin and install a syslogd. There are also a a number of free and commercial syslogd-like tools for windows that receive logs by various means, including RFC3164, if thats what you want. I see no need to develop another "syslogd" for windows - there are plenty already.
I agree, it is not the responsability of Boost.Log to provide a a POSIX-compliant syslog API implementation on every platform, in particular on Windows.
This has been a long thread of violent agreement re the undesirability of yet another syslogd afaiks. This has nothing to do with whether boost log, claiming to be a cross platform logging library, should support generating and sending RFC3164 messages. I belive it should, as this is a (the?) major cross platform logging method, used by everything from network equipment to servers. A useful RFC3164 sender capability would seem to require only the development of a sink able to format messages in accordance with RFC3164 and send them over UDP. The formatting requires extracting a priority and timestamp from the message being logged to build the header (this also requires the host name or IP and the process/program name to be known to the sink). The message content field format is freeform/not specified by RFC3164 and should simply contain a readable formatted message. I don't see any particular difficulty in implementing such a sink?

Darryl Green wrote:
As for Boost.Log, once the POSIX API is implemented on Windows, it will be supported by Boost.Log right away.
What exactly do you mean by the vague reference to the "posix syslog API"?
From the man page I see that the API is defined in POSIX.1-2001. http://linux.die.net/man/3/syslog That is what I refer to as POSIX-compliant syslog API.
Windows (if you install SFU) has a posix API and guess what - it includes a syslogd. Similarly, you can run cygwin and install a syslogd.
Then Boost.Log already supports syslog on Windows, if you install SFU or Cygwin. I'm not sure it is an often used configuration, though.
There are also a a number of free and commercial syslogd-like tools for windows that receive logs by various means, including RFC3164, if thats what you want.
I see no need to develop another "syslogd" for windows - there are plenty already.
Yes, there are a lot of syslog servers, but I haven't seen any native client APIs, except for Cygwin. If you know one, please, tell me.
This has been a long thread of violent agreement re the undesirability of yet another syslogd afaiks.
This has nothing to do with whether boost log, claiming to be a cross platform logging library, should support generating and sending RFC3164 messages. I belive it should, as this is a (the?) major cross platform logging method, used by everything from network equipment to servers.
A useful RFC3164 sender capability would seem to require only the development of a sink able to format messages in accordance with RFC3164 and send them over UDP.
... or TCP. And, perhaps, with an encryption layer. Yet again, I consider syslog as an API, not just some protocol. This API is also standardized and can be used outside of Boost. I think that having this API on Windows has an additional benefit. Therefore I think it should be implemented as a separate project.
I don't see any particular difficulty in implementing such a sink?
Technically, there may not be difficulties. But I don't think it's reasonable.

Andrey Semashev wrote:
Darryl Green wrote:
I see no need to develop another "syslogd" for windows - there are plenty already.
Yes, there are a lot of syslog servers, but I haven't seen any native client APIs, except for Cygwin. If you know one, please, tell me.
However, after googling around I found this project: http://syslog-win32.sourceforge.net/ It looks like this is what we were looking for. I'll see if I can compile Boost.Log with it.

Andrey Semashev:
Yet again, I consider syslog as an API, not just some protocol. This API is also standardized and can be used outside of Boost. I think that having this API on Windows has an additional benefit. Therefore I think it should be implemented as a separate project.
I think I see where you're coming from: you consider the syslog function a frontend to the syslogd daemon and, from your point of view, a "sink". This is, on its surface, reasonable, but it ignores the use cases: 1. How do I write a program that can be configured to send RFC3164 messages to a specific machine? 2. How do I port a program that uses the syslog function to Windows? Regarding (1), your proposed solution is for people to require their users to install a syslogd daemon for Windows. This is unacceptable for various reasons. A program that can perform its functions from user space should not install a Windows service, and it would be difficult to coordinate several such programs to not install conflicting syslogd services. An alternative might be to implement syslog.lib that does whatever syslogd does, but from user space. But this duplicates a significant portion of the Boost.Log goals and functionality; it is effectively a direct competitor to Boost.Log. Regarding (2), it makes perfect sense for Boost.Log to offer a boost::syslog function as a frontend. This makes porting easy and allows the program to use Boost.Log's features to centrally filter and route the log messages.

Peter Dimov wrote:
Andrey Semashev:
Yet again, I consider syslog as an API, not just some protocol. This API is also standardized and can be used outside of Boost. I think that having this API on Windows has an additional benefit. Therefore I think it should be implemented as a separate project.
I think I see where you're coming from: you consider the syslog function a frontend to the syslogd daemon and, from your point of view, a "sink".
This is, on its surface, reasonable, but it ignores the use cases:
1. How do I write a program that can be configured to send RFC3164 messages to a specific machine?
2. How do I port a program that uses the syslog function to Windows?
Regarding (1), your proposed solution is for people to require their users to install a syslogd daemon for Windows. This is unacceptable for various reasons. A program that can perform its functions from user space should not install a Windows service, and it would be difficult to coordinate several such programs to not install conflicting syslogd services.
I don't see how including syslog API implementation into Boost.Log can help you with this. You will have to install the syslog daemon somewhere anyway. If not on the machine where your application runs, then on some remote server. And I think that any conflict between several applications using different syslog implementations is not relevant to Boost.Log and at least is solvable as long as there exists a single daemon that conforms to the syslog protocol specification. This daemon can be used for multiple applications. IOW, I see the following scheme quite viable: Application A links with syslog API implementation X. Application B links with syslog API implementation Y. Either of the applications A or B may or may not use Boost.Log. Both X and Y send syslog messages to the daemon Z, which may or may not be part of X or Y distribution. Z may be an independent project at all. There are plenty of Zs already, including the Windows platform. I've found an example of X or Y here: http://syslog-win32.sourceforge.net/ Why would I need to include this functionality into Boost.Log?
An alternative might be to implement syslog.lib that does whatever syslogd does, but from user space. But this duplicates a significant portion of the Boost.Log goals and functionality; it is effectively a direct competitor to Boost.Log.
I never suggested reimplementing syslog daemon in a user-space library. I agree that this is quite pointless, especially since there are implemented daemons out there.
Regarding (2), it makes perfect sense for Boost.Log to offer a boost::syslog function as a frontend. This makes porting easy and allows the program to use Boost.Log's features to centrally filter and route the log messages.
Although hypothetically it looks possible to wrap the whole Boost.Log into a library that exposes POSIX syslog API, this would be a quite heavy solution. The syslog API is quite simple and C-oriented, it doesn't need all the bells and whistles that Boost.Log provides. Besides, it occurs to me that syslog API is a low-level instrument, and Boost.Log should build on to of it. Imagine for a moment that Pthreads are implemented over Boost.Thread - it looks quite odd to me. Therefore applications that are explicitly tied with syslog API are better to be ported with a simple and straightforward implementation of this API, like the one I posted above.

On Sun, 2009-02-15 at 16:27 +0300, Andrey Semashev wrote:
Peter Dimov wrote:
Andrey Semashev:
Yet again, I consider syslog as an API, not just some protocol. This
#include <syslog.h> void openlog(const char *ident, int option, int facility); void syslog(int priority, const char *format, ...); void closelog(void); #include <stdarg.h> void vsyslog(int priority, const char *format, va_list ap); Now, this API, by itself is problematic. It assumes a syslogd. The whole idea of a syslogd assumes a security modem where opening low numbered ports requires root priveledges. The openlog options are largely platform dependent as well. What it reduces to is a C printf style interface to generating textual log message bodies, the only work done behind the scenes that is in any way portable is to prepend to the resulting string the facility and priority information and to send this to the mysterions syslogd by a mechanism not defined here. In practice, the way this is done is by taking the resulting message and sending it over a unix domain socket to /dev/log.
API is also standardized and can be used outside of Boost. I think that having this API on Windows has an additional benefit. Therefore I think it should be implemented as a separate project.
It is, already. Why are we still discussing this?
I think I see where you're coming from: you consider the syslog function a frontend to the syslogd daemon and, from your point of view, a "sink".
This is, on its surface, reasonable, but it ignores the use cases:
1. How do I write a program that can be configured to send RFC3164 messages to a specific machine?
2. How do I port a program that uses the syslog function to Windows?
Regarding (1), your proposed solution is for people to require their users to install a syslogd daemon for Windows. This is unacceptable for various reasons. A program that can perform its functions from user space should not install a Windows service, and it would be difficult to coordinate several such programs to not install conflicting syslogd services.
I don't see how including syslog API implementation into Boost.Log can help you with this.
A posix syslog() call can only log to the daemon. Daemon config controls distrobution from there. Now, if you enforce the syslog "security" mechanism that will only accept datagrams with a source port of 514, and you have multiple apps try to bind to 514, you will be in trouble, it won't work. If instead you allow an arbitrary source port (which is fine - in reality "restricted" source ports provide no network security) you can have as many independently configured sinks, each logging to any destination, local or remote, as you like.
You will have to install the syslog daemon somewhere anyway. If not on the machine where your application runs, then on some remote server. And
Assume I already have syslog infrastructure. I don't want to replace it. I use it to log messages from a whole range of (remote) sources.
I think that any conflict between several applications using different syslog implementations is not relevant to Boost.Log and at least is solvable as long as there exists a single daemon that conforms to the syslog protocol specification. This daemon can be used for multiple applications.
As you are obviously aware, having already implemented a sink using it, the syslog API (really, the RFC3164 message format) provides only very limited message routing/filtering fields. As soon as you rely on it to route messages, you have lost one of the main features of your proposed logging library - extensible and flexible message routing/filtering.
IOW, I see the following scheme quite viable:
Application A links with syslog API implementation X.
Application B links with syslog API implementation Y.
Err - no. Using more than one is not guaranteed to work - unless... See below.
Either of the applications A or B may or may not use Boost.Log.
Ok.
Both X and Y send syslog messages to the daemon Z, which may or may not be part of X or Y distribution. Z may be an independent project at all.
The only publicly defined, portable interface to a syslog daemon is RFC3164. There is no guarantee that a given platform/environment/whatever you want to call it uses the same protocol as another to communicate between a syslog client and a local syslogd. Thats the "err - no" above.
There are plenty of Zs already, including the Windows platform. I've found an example of X or Y here:
Which more or less proves my point that a syslog "client" impl is trivial, and the portable interface from the client to the daemon is RFC3164...
Why would I need to include this functionality into Boost.Log?
So you can combine the power of boost log message routing with the abilty to route messages to any/many syslog daemons/sinks, be they local or remote.
An alternative might be to implement syslog.lib that does whatever syslogd does, but from user space. But this duplicates a significant portion of the Boost.Log goals and functionality; it is effectively a direct competitor to Boost.Log.
syslogd is always user space.
I never suggested reimplementing syslog daemon in a user-space library. I agree that this is quite pointless, especially since there are implemented daemons out there.
daemon = long running user space process with no attached console.
Regarding (2), it makes perfect sense for Boost.Log to offer a boost::syslog function as a frontend. This makes porting easy and allows the program to use Boost.Log's features to centrally filter and route the log messages.
Nice. I hadn't though about that (I was more interested in a lightweight ability to log to existing syslog infrastructure). But of course all the facilities needed for a syslog "daemon" are already in boost log except for the ability to construct a log message from an received RFC3164 message.
Although hypothetically it looks possible to wrap the whole Boost.Log into a library that exposes POSIX syslog API, this would be a quite heavy solution. The syslog API is quite simple and C-oriented, it doesn't need all the bells and whistles that Boost.Log provides.
Doesn't need/doesn't provide - aren't you arguing against your own objections to implementing RFC3164 logging without going through the syslog API now?
Besides, it occurs to me that syslog API is a low-level instrument, and Boost.Log should build on to of it. Imagine for a moment that Pthreads are implemented over Boost.Thread - it looks quite odd to me.
If you built pthreads over boost thread you would restrict its capabilites somewhat due to restrictions in boost thread. +/- some syntactic nicities, RAII etc boost thread is a subset of pthreads. If boost log's ambitions were only to be a C++ "view" of a portable subset of syslog then your comparison might have some relevance (and the lib wouldn't get accepted).
Therefore applications that are explicitly tied with syslog API are better to be ported
What are these apps tied to the syslog API that you are talking about porting?
with a simple and straightforward implementation of this API, like the one I posted above.
I agree that porting an app that uses syslog can generally be done most easily by providing the sylog API - that would be an example of Peter Dimov's (2) above? The only part of the API required for a sender (1 above) is the part that builds a message from a few fields passed somewhat arcanely through the syslog() call and sends the result to UDP port 514. Surely it would be easier to create such a message directly using the boost log attribute and formatting system and send it, while at the same time gaining the ability to route to multiple, local and/or remote, syslog daemon "sinks"?

Darryl Green wrote:
Now, this API, by itself is problematic. It assumes a syslogd.
All these are your assumptions. I don't see any of these functions require syslogd or /dev/log. However, I admit that often this API is implemented that way.
A posix syslog() call can only log to the daemon. Daemon config controls distrobution from there. Now, if you enforce the syslog "security" mechanism that will only accept datagrams with a source port of 514, and you have multiple apps try to bind to 514, you will be in trouble, it won't work.
You mean when multiple apps run on the same machine, right? How implementing the syslog protocol in Boost.Log helps with this then? In fact, using the native implementation (if there is one) is more preferable in this case, since it may use some opaque access to local syslogd (the one that you implied in your post), that would allow multiple apps to log simultaneously. Moreover, as this access is provided by OS I would expect it to be authorized by security policies that may be in action, as opposed to raw usage of port 514.
If instead you allow an arbitrary source port (which is fine - in reality "restricted" source ports provide no network security) you can have as many independently configured sinks, each logging to any destination, local or remote, as you like.
As you are obviously aware, having already implemented a sink using it, the syslog API (really, the RFC3164 message format) provides only very limited message routing/filtering fields. As soon as you rely on it to route messages, you have lost one of the main features of your proposed logging library - extensible and flexible message routing/filtering.
Ok, consider me convinced on this part. I will add portable RFC3164 support to Boost.Log, as it will help to route log records better.
IOW, I see the following scheme quite viable:
Application A links with syslog API implementation X.
Application B links with syslog API implementation Y.
Err - no. Using more than one is not guaranteed to work - unless... See below.
Both X and Y send syslog messages to the daemon Z, which may or may not be part of X or Y distribution. Z may be an independent project at all.
The only publicly defined, portable interface to a syslog daemon is RFC3164. There is no guarantee that a given platform/environment/whatever you want to call it uses the same protocol as another to communicate between a syslog client and a local syslogd. Thats the "err - no" above.
Well, a "syslogd" that doesn't support RFC3164 (even from local processes) is not syslogd as I see it. I agree that it can provide an additional, internal interface that can be utilized by the syslog() call. And speaking of it, for the reasons I mentioned above, it may be perfectly reasonable to provide support for the native syslog API, if it's available.
Although hypothetically it looks possible to wrap the whole Boost.Log into a library that exposes POSIX syslog API, this would be a quite heavy solution. The syslog API is quite simple and C-oriented, it doesn't need all the bells and whistles that Boost.Log provides.
Doesn't need/doesn't provide - aren't you arguing against your own objections to implementing RFC3164 logging without going through the syslog API now?
I'm not sure I understand you. All I'm saying that Boost.Log is too heavy to implement the syslog API (the syslog() call, if you prefer). Or were you talking about implementing syslogd on top of Boost.Log? If so, then I agree, this would be quite possible.
If you built pthreads over boost thread you would restrict its capabilites somewhat due to restrictions in boost thread. +/- some syntactic nicities, RAII etc boost thread is a subset of pthreads.
I must be missing something about pthreads, but I always thought of Boost.Thread as of a far more flexible, while sometimes more heavyweight instrument than pthreads.
If boost log's ambitions were only to be a C++ "view" of a portable subset of syslog then your comparison might have some relevance (and the lib wouldn't get accepted).
It isn't, yet. :)

On Mon, 2009-02-16 at 20:41 +0300, Andrey Semashev wrote:
Darryl Green wrote:
Now, this API, by itself is problematic. It assumes a syslogd.
All these are your assumptions. I don't see any of these functions require syslogd or /dev/log. However, I admit that often this API is implemented that way.
Not mine, posix's.
A posix syslog() call can only log to the daemon. Daemon config controls distrobution from there. Now, if you enforce the syslog "security" mechanism that will only accept datagrams with a source port of 514, and you have multiple apps try to bind to 514, you will be in trouble, it won't work.
You mean when multiple apps run on the same machine, right?
Yes.
How implementing the syslog protocol in Boost.Log helps with this then?
It won't unless you do what is described below. I've been trying to guess what it is that makes you think there needs to be the one and only syslogd on a system that is a source of messages to be consumed by syslog. This is one historical reason machine X syslogd collects messages locally, say via unix domain socket, and sends them via 514 to remote syslogd on machine Y. Y trusts X's admin and the network in between. Of course in the real/modern world this is all just historical nonsense.
In fact, using the native implementation (if there is one) is more preferable in this case, since it may use some opaque access to local syslogd (the one that you implied in your post), that would allow multiple apps to log simultaneously.
My point was in reaction to your suggestion you could mix and match the thing you refer to as the syslog API with different syslogd implementations.
Moreover, as this access is provided by OS I would expect it to be authorized by security policies that may be in action, as opposed to raw usage of port 514.
Agreed. As per following.
If instead you allow an arbitrary source port (which is fine
As you are obviously aware, having already implemented a sink using it, the syslog API (really, the RFC3164 message format) provides only very limited message routing/filtering fields. As soon as you rely on it to route messages, you have lost one of the main features of your proposed logging library - extensible and flexible message routing/filtering.
Ok, consider me convinced on this part. I will add portable RFC3164 support to Boost.Log, as it will help to route log records better.
Cool. Thats all I did want. And all I didn't want was to run a syslogd on the box the app was on. This addresses both.
IOW, I see the following scheme quite viable:
Application A links with syslog API implementation X.
Application B links with syslog API implementation Y.
Err - no. Using more than one is not guaranteed to work - unless... See below.
Both X and Y send syslog messages to the daemon Z, which may or may not be part of X or Y distribution. Z may be an independent project at all.
The only publicly defined, portable interface to a syslog daemon is RFC3164. There is no guarantee that a given platform/environment/whatever you want to call it uses the same protocol as another to communicate between a syslog client and a local syslogd. Thats the "err - no" above.
Well, a "syslogd" that doesn't support RFC3164 (even from local processes) is not syslogd as I see it. I agree that it can provide an additional, internal interface that can be utilized by the syslog() call. And speaking of it, for the reasons I mentioned above, it may be perfectly reasonable to provide support for the native syslog API, if it's available.
Hmm. We seem to be in violent agreement again. We agree that portable way to get something to any syslogd (loal or remote) is RFC3164 and we agree that on a posix box you should use the syslog() API to log to the local syslogd, and that boost log should support both. Excellent.
Doesn't need/doesn't provide - aren't you arguing against your own objections to implementing RFC3164 logging without going through the syslog API now?
I'm not sure I understand you.
Never mind. It just seemed the arguments you were using re how limited syslog API was, and hence why boost log should not be used to implement it, were the same reasons that boost log should directly support sending RFC3164 messages....
Or were you talking about implementing syslogd on top of Boost.Log? If so, then I agree, this would be quite possible.
That was Peter Dimov's (2) suggestion, in effect. I like it but it isn't as core to what I at least see the job of a logging lib as being as the ability to send (Peter's (1)).
I must be missing something about pthreads, but I always thought of Boost.Thread as of a far more flexible, while sometimes more heavyweight instrument than pthreads.
They are almost 1:1 - with pthreads offering a few extra attributes that can be controlled.

Andrey Semashev writes:
Ok, consider me convinced on this part. I will add portable RFC3164 support to Boost.Log, as it will help to route log records better.
It turned out implementing a simple rfc3164-based logger is not all that difficult, really. I guess the biggest effort would be to integrate it meaningfully into Boost.Log. Anyway, here's the source code, in case any finds it useful. Take care, Peter #include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/assert.hpp> #include <boost/test/prg_exec_monitor.hpp> #include <boost/lexical_cast.hpp> #include <boost/array.hpp> #include <iostream> namespace rfc3164 { namespace type { enum facility_type { kernel_message = 0 , user_message = 1 , mail_system = 2 , system_daemon = 3 , authorization = 4 , internal = 5 , line_printer = 6 , network_news = 7 , uucp = 8 , clock_daemon = 9 , security = 10 , ftp_daemon = 11 , ntp_daemon = 12 , log_audit = 13 , log_alert = 14 , clock_daemon2 = 15 , local0 = 16 , local1 = 17 , local2 = 18 , local3 = 19 , local4 = 20 , local5 = 21 , local6 = 22 , local7 = 23 }; enum priority_type { emergency = 0 , alert = 1 , critical = 2 , error = 3 , warning = 4 , notice = 5 , info = 6 , debug = 7 }; } using namespace type; class message { public: typedef boost::asio::const_buffer const_buffer; typedef boost::array<const_buffer, 2u> iovec; message(facility_type facility, priority_type pri, const_buffer msg) { int const code( static_cast<int>(facility) * 8 + static_cast<int>(pri) ); _prefix = '<' + boost::lexical_cast<std::string>(code) + '>'; _iov[0] = boost::asio::buffer(_prefix); _iov[1] = msg; } iovec const & iov() const { return _iov; } private: std::string _prefix; iovec _iov; }; class server { public: typedef boost::asio::ip::udp inet; static inet::endpoint endpoint(std::string const & host, unsigned short port = 514u) { return inet::endpoint(boost::asio::ip::address::from_string(host), port); } server(inet::endpoint const & destination = endpoint("127.0.0.1", 514u)) : _s(_ios, inet::endpoint(destination.protocol(), 0)) { _s.connect(destination); } void send(facility_type facility, priority_type pri, char const * msg) { _s.send(message(facility, pri, boost::asio::const_buffer(msg, std::strlen(msg))).iov()); } private: boost::asio::io_service _ios; boost::asio::ip::udp::socket _s; }; } int cpp_main(int argc, char ** argv) { using namespace rfc3164::type; rfc3164::server log; log.send(user_message, info, "this is a meaningful test message"); return 0; }

On Sun, 2009-02-15 at 12:31 +0300, Andrey Semashev wrote:
Darryl Green wrote:
As for Boost.Log, once the POSIX API is implemented on Windows, it will be supported by Boost.Log right away.
What exactly do you mean by the vague reference to the "posix syslog API"?
From the man page I see that the API is defined in POSIX.1-2001.
http://linux.die.net/man/3/syslog
That is what I refer to as POSIX-compliant syslog API.
Fair enough. But like any/many small interfaces to the beast that is the posix system model, you can't really consider it in isolation. It makes all sorts of assumptions about the platform/environment (some are largely historical on any platform now).
Windows (if you install SFU) has a posix API and guess what - it includes a syslogd. Similarly, you can run cygwin and install a syslogd.
Then Boost.Log already supports syslog on Windows, if you install SFU or Cygwin. I'm not sure it is an often used configuration, though.
Only if you build your app against cygwin or SFL. If you don't, but you write a triavial app that sends RFC3164 messages (actually, given RFC3164s preference to make an effort to log anything at all, that might as well be "any chunk of text") over UDP to localhost:514 you should see - log messages!
There are also a a number of free and commercial syslogd-like tools for windows that receive logs by various means, including RFC3164, if thats what you want.
I see no need to develop another "syslogd" for windows - there are plenty already.
Yes, there are a lot of syslog servers, but I haven't seen any native client APIs, except for Cygwin. If you know one, please, tell me.
You can't separate the client and server impl unless you put an open interface in between RFC3164 is that interface. Use it!
A useful RFC3164 sender capability would seem to require only the development of a sink able to format messages in accordance with RFC3164 and send them over UDP.
... or TCP. And, perhaps, with an encryption layer.
What logging standard/spec/protocol/system are you refering to? There is no such facility for syslog. There is no such facility in RFC3164. Nobody has asked for it. TCP for log messages is a bad idea. Don't send syslog over insecure channels. Use IPSec.
Yet again, I consider syslog as an API, not just some protocol. This API is also standardized and can be used outside of Boost. I think that
You and I have a very different view of "protocol" and "API". The tiny bit of spec that is the man page for syslog is "just an" API. RFC3164 is a (small and simple) protocol but still provides a far more detailed specification of interface and behaviour.
having this API on Windows has an additional benefit. Therefore I think it should be implemented as a separate project.
I don't know who you are trying to convince re the syslog API on windows. Who asked for it/wants it and/or isn't satisfied with existing solutions?
I don't see any particular difficulty in implementing such a sink?
Technically, there may not be difficulties. But I don't think it's reasonable.
What isn't reasonable? To provide apps with the ability to log to what is probably the most widely deployed remote logging system in the world without installing some service/daemon? Is it unreasonable to ask for remote logging sender functionality to be hightly portable - to any platform with BSD-style sockets API, without any reliance on some syslogd being installed?

On Mon, 2009-02-16 at 22:36 +1000, Darryl Green wrote:
On Sun, 2009-02-15 at 12:31 +0300, Andrey Semashev wrote:
Darryl Green wrote:
I don't see any particular difficulty in implementing such a sink?
Technically, there may not be difficulties. But I don't think it's reasonable.
I started trying to hack about the syslog sink to directly generate and send an RFC3164 message. I'm not quite sure how one should use the formatters and/or how to do a suitably general mapping of attributes to RFC3164 message fields. I need to do something like this: ostringstream ss; ss << "<" facility * 8 + level << ">" << fmt::date_time< types
("DateTime", fmt::keywords::format = "%b %d %H:%M:%S")) << " " << host_name << " " << program_name << ": " << formatted_message; std::string s = ss.str(); send(sock, s.c_str(), s.size());
Suggestions?

Darryl Green wrote:
I started trying to hack about the syslog sink to directly generate and send an RFC3164 message. I'm not quite sure how one should use the formatters and/or how to do a suitably general mapping of attributes to RFC3164 message fields. I need to do something like this:
ostringstream ss; ss << "<" facility * 8 + level << ">" << fmt::date_time< types
("DateTime", fmt::keywords::format = "%b %d %H:%M:%S")) << " " << host_name << " " << program_name << ": " << formatted_message; std::string s = ss.str(); send(sock, s.c_str(), s.size());
Suggestions?
I think, the RFC3164 packet structure should not be achieved with formatters, at least not those exposed to the user. The protocol is the sink's implementation detail.

Darryl Green wrote:
A useful RFC3164 sender capability would seem to require only the development of a sink able to format messages in accordance with RFC3164 and send them over UDP. ... or TCP. And, perhaps, with an encryption layer.
What logging standard/spec/protocol/system are you refering to? There is no such facility for syslog. There is no such facility in RFC3164. Nobody has asked for it. TCP for log messages is a bad idea.
http://tools.ietf.org/html/rfc3195 It certainly will be asked for, eventually.
Don't send syslog over insecure channels. Use IPSec.
The point is not only in security, but also in delivery reliability and order. UDP doesn't provide that.

Peter Simons wrote:
Hi Andrey,
I totally agree that lack of [syslog support] on Windows is a huge gap. However, I believe such a project should be standalone, and probably outside of Boost.
in my humble opinion, platform-independence is one of the key benefits that I'd expect from using a library such as Boost.Log. If your library doesn't provide that, then I would not want to see it included in Boost.
If you provide the syslog client API implementation for Windows, I'm sure the library will work out of box with it. The library does not aim to reimplement every native API it uses, it simply allows to employ different ways of logging in a unified manner. And, maybe, a little more. This may not be enough for your needs, but I believe others might find it useful.

On Sun, Feb 8, 2009 at 5:58 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
After a long time of documenting, polishing and testing I'm glad to announce that Boost.Log has reached the level where public review request can be submitted. The automatic tests aren't entirely complete, however, the basic functionality is covered and most of what is not covered has been tried by hand.
[snip...]
Comments are welcome.
Hi, Andrey First of all, thank you for your great efforts in creating and submitting logging library to boost. As for me, logging library is the most long-desired one to be in boost. I've spent several hours (frankly speaking, several ten hours ;) ) writing simple test applications that use boost::log. My goal was to check if this library will satisfy our product's requirements for logging (Unfortunately, we don't have uniform logging solution at the moment). Well, at first glance boost::log has almost everything that any sophisticated user or programmer could except! My testing platform was: RHEL4 gcc (GCC) 4.1.2 20071124 (Red Hat 4.1.2-42). I've used boost 1.38.0 and latest boost.log downloaded from vault. I didn't discovered any issues except 2. 1 (minor): annoying warnings like 'class aaa has virtual functions but non-virtual destructor' with kilobytes of related messages ('in instantiation of bla-bla ... instantiated from here' etc) 2 (major): rotating_ofstream seems not working correctly when std::ios_base::app flag passed to rotating_ofstream ctor (or open function). In case of using that flag no file is created. That's because in rotating_ofstream.hpp, file_controller_base ctor m_OpenMode is generated as: m_OpenMode |= std::ios_base::out | std::ios_base::trunc; m_OpenMode &= ~std::ios_base::in; ios_base::trunc and ios_base::app flags are "conflicting" (at least in my stdcxx). So, the file is not opened. I've also noticed that rotation is working only for one program run (even if ios_base::app open mode is used). I.e., I have application with static output to log. At first run 4 log files are created. At second run log file count is the same - 4. In my expectation, it should be 8. (By the way, python logging module generates 8 files for the same scenario if using logging.handlers.RotatingFileHandler). Also, I have minor feature request related to rotating file naming. I will be nice to have current active log file name as: 'file.log'. And the others as file.log.1, file.log.2 etc (i.e., name pattern is not applied to active log file). Regards

Alexander Arhipenko wrote:
1 (minor): annoying warnings like 'class aaa has virtual functions but non-virtual destructor' with kilobytes of related messages ('in instantiation of bla-bla ... instantiated from here' etc)
Yes, these warnings were reported by others, too. I've fixed them (at least, I hope so) in CVS HEAD.
2 (major): rotating_ofstream seems not working correctly when std::ios_base::app flag passed to rotating_ofstream ctor (or open function). In case of using that flag no file is created. That's because in rotating_ofstream.hpp, file_controller_base ctor m_OpenMode is generated as:
m_OpenMode |= std::ios_base::out | std::ios_base::trunc; m_OpenMode &= ~std::ios_base::in;
ios_base::trunc and ios_base::app flags are "conflicting" (at least in my stdcxx). So, the file is not opened.
True. I forgot about the "app" flag, indeed. However, what behavior were you trying to achieve with this flag? It doesn't occur to me that it has much sense with the rotating stream.
I've also noticed that rotation is working only for one program run (even if ios_base::app open mode is used). I.e., I have application with static output to log. At first run 4 log files are created. At second run log file count is the same - 4. In my expectation, it should be 8. (By the way, python logging module generates 8 files for the same scenario if using logging.handlers.RotatingFileHandler).
I see. I guess the problem is that the stream does not scan the output directory for other files. I'll try to fix that.
Also, I have minor feature request related to rotating file naming. I will be nice to have current active log file name as: 'file.log'. And the others as file.log.1, file.log.2 etc (i.e., name pattern is not applied to active log file).
Looks like the rotation functionality needs to be extended quite considerably, as I have received other requests for different rotation schemes. I'll have to think about how to implement this extension better.

On Sat, Feb 14, 2009 at 5:34 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
[...snip]
True. I forgot about the "app" flag, indeed. However, what behavior were you trying to achieve with this flag? It doesn't occur to me that it has much sense with the rotating stream.
Andrey, consider following use case. Application that runs on remote server (let's call that application slave) is started up several times per day by another process (master). Slave is writing logs to it's own log file (e.g., slave.log). This log file is monitored by administrator every day (notification email with attached latest log files is sent to him). In case if using log rotation without 'app' flag, slave.log will be overwritten every time slave is starting up, so valuable log records could be overlooked by administrator. Also, according to my own intuition and to another logging libaries (python.logging), the first log file in rotation sequence, e.g. file.log.0, usually contains latest log records. And the last file (e.g., file.log.N), contains the earliest ones. It will be nice to see such behavior in rotating_ofstream. Regards

Alexander Arhipenko wrote:
On Sat, Feb 14, 2009 at 5:34 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
[...snip]
True. I forgot about the "app" flag, indeed. However, what behavior were you trying to achieve with this flag? It doesn't occur to me that it has much sense with the rotating stream.
Andrey, consider following use case. Application that runs on remote server (let's call that application slave) is started up several times per day by another process (master). Slave is writing logs to it's own log file (e.g., slave.log). This log file is monitored by administrator every day (notification email with attached latest log files is sent to him). In case if using log rotation without 'app' flag, slave.log will be overwritten every time slave is starting up, so valuable log records could be overlooked by administrator.
So you want to have logs from several runs in one file, right?
Also, according to my own intuition and to another logging libaries (python.logging), the first log file in rotation sequence, e.g. file.log.0, usually contains latest log records. And the last file (e.g., file.log.N), contains the earliest ones. It will be nice to see such behavior in rotating_ofstream.
That is a possible naming scheme, while I find it counter-intuitive. Maybe because I'm not familiar with python. Or maybe because it doesn't compose well with naming schemes that use date and time. All in all, I have extending rotation flexibility in the library TODO list.

On Tue, Feb 17, 2009 at 5:47 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
So you want to have logs from several runs in one file, right?
Exactly
That is a possible naming scheme, while I find it counter-intuitive. Maybe because I'm not familiar with python. Or maybe because it doesn't compose well with naming schemes that use date and time.
All in all, I have extending rotation flexibility in the library TODO list.
Thanks, will be waiting for the new releases Regards
participants (15)
-
Alexander Arhipenko
-
Alp Mestan
-
Andrey Semashev
-
Boris Schaeling
-
Christopher Jefferson
-
Darryl Green
-
Dmitry Goncharov
-
Edouard A.
-
Hansi
-
Peter Dimov
-
Peter Simons
-
Ravi
-
Steven Watanabe
-
Vicente Botet
-
vicente.botet