...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Initially scoped attributes were able to override other attributes with the same name if they were already registered by the time when a scoped attribute encountered. This allowed some interesting use cases like this:
BOOST_LOG_DECLARE_GLOBAL_LOGGER(my_logger, src::logger_mt) void foo() { // This scoped attribute would temporarily replace the existing tag BOOST_LOG_SCOPED_THREAD_TAG("Section", std::string, "In foo"); // This log record will have a "Section" attribute with value "In foo" BOOST_LOG(get_my_logger()) << "We're in foo section"; } int main(int, char*[]) { BOOST_LOG_SCOPED_THREAD_TAG("Section", std::string, "In main"); // This log record will have a "Section" attribute with value "In main" BOOST_LOG(get_my_logger()) << "We're in main section"; foo(); // This log record will have a "Section" attribute with value "In main" again BOOST_LOG(get_my_logger()) << "We're in main section again"; return 0; }
However, this feature introduced a number of safety problems, including thread safety issues, that could be difficult to track down. For example, it was no longer safe to use logger-wide scoped attributes on the same logger from different threads, because the resulting attribute would be undefined:
BOOST_LOG_DECLARE_GLOBAL_LOGGER(my_logger, src::logger_mt) void thread1() { BOOST_LOG_SCOPED_LOGGER_TAG(get_my_logger(), "Tag", std::string, "thread1"); BOOST_LOG(get_my_logger()) << "We're in thread1"; } void thread2() { BOOST_LOG_SCOPED_LOGGER_TAG(get_my_logger(), "Tag", int, 10); BOOST_LOG(get_my_logger()) << "We're in thread2"; } int main(int, char*[]) { BOOST_LOG_SCOPED_LOGGER_TAG(get_my_logger(), "Tag", double, -2.2); BOOST_LOG(get_my_logger()) << "We're in main"; boost::thread t1(&thread1); boost::thread t2(&thread2); t1.join(); t2.join(); // Which "Tag" is registered here? BOOST_LOG(get_my_logger()) << "We're in main again"; return 0; }
There were other issues, like having an attribute set iterator that points to one attribute object, then suddenly without seemingly modifying it it becomes pointing to a different attribute object (of, possibly, a different type). Such behavior could lead to tricky failures that would be difficult to investigate. Therefore this feature was eventually dropped, which simplified the scoped attributes implementation significantly.