[log] v2 Initialisation, default sink behaviour and filtering documentation

Hi, I'm in the process of adopting a logging library, so the timing of the Boost.Log v2 "status report" - for me - could not have been better. :) This library is awesome, thank you for making it! -- I am in the process of moving beyond the default sink now, and had some issues. I tried to add the sinks after my logger object had been default initialized, and this caused some problems (partial streams/corruption, mostly). Currently I'm calling core->remove_all_sinks() to remove the default sink. Are there any "best practices" here? Perhaps it would be a good idea to add these "requirements" to the documentation, if they are not there already and I missed them? :) -- I also noticed that the severity filter examples are : logging::core::get()->set_filter ( logging::trivial::severity >= logging::trivial::info );
From "Setting up sinks", and
sink->set_filter(expr::attr< int >("Severity") >= 2); (i.e. comparing the Severity with an int) when moving to the more advanced section in "Sink frontends". Could you adjust one of the examples in "Sink frontends" to use the severity_level type (that the documentation introduces in the tutorial "Adding more information to log: Attributes") directly? For example: sink->set_filter(expr::attr< severity_level >("Severity") >= warning); Or explaining this in "Log record formatting". I had trouble understanding this at first, but I might be the only one :). Thought I'd mention it anyway. -- Regards, Mats Taraldsvik Norkart AS norkart.no

On January 23, 2013 6:38:45 PM Mats Taraldsvik <mats.taraldsvik@norkart.no> wrote:
Hi,
I am in the process of moving beyond the default sink now, and had some issues. I tried to add the sinks after my logger object had been default initialized, and this caused some problems (partial streams/corruption, mostly). Currently I'm calling core->remove_all_sinks() to remove the default sink. Are there any "best practices" here? Perhaps it would be a good idea to add these "requirements" to the documentation, if they are not there already and I missed them? :)
The default sink cannot be removed, not even with remove_all_sinks. It is used implicitly when no other sinks are added to the core. When you add your sink to the core you automatically suppress the use of the default sink. As for your problem, could you describe it in more details? A minimal code sample would be useful.
--
I also noticed that the severity filter examples are :
logging::core::get()->set_filter ( logging::trivial::severity >= logging::trivial::info );
From "Setting up sinks", and
sink->set_filter(expr::attr< int >("Severity") >= 2);
(i.e. comparing the Severity with an int) when moving to the more advanced section in "Sink frontends".
Could you adjust one of the examples in "Sink frontends" to use the severity_level type (that the documentation introduces in the tutorial "Adding more information to log: Attributes") directly? For example:
sink->set_filter(expr::attr< severity_level >("Severity") >= warning);
Or explaining this in "Log record formatting".
I had trouble understanding this at first, but I might be the only one :). Thought I'd mention it anyway.
The type of severity level is not mandated by the library, and each section of the documentation is intended to have minimal dependencies on other parts of the library. That's why trivial severity levels are not used in sinks description. I'll think about how to clear this confusion better.

Hi Andrey,
-----Opprinnelig melding----- Fra: Boost [mailto:boost-bounces@lists.boost.org] På vegne av Andrey Semashev Sendt: 24. januar 2013 04:30 Til: boost@lists.boost.org Emne: Re: [boost] [log] v2 Initialisation, default sink behaviour and filtering documentation
On January 23, 2013 6:38:45 PM Mats Taraldsvik <mats.taraldsvik@norkart.no> wrote:
Hi,
I am in the process of moving beyond the default sink now, and had some issues. I tried to add the sinks after my logger object had been default initialized, and this caused some problems (partial streams/corruption, mostly). Currently I'm calling core->remove_all_sinks() to remove the default sink. Are there any "best practices" here? Perhaps it would be a good idea to add these "requirements" to the documentation, if they are not there already and I missed them? :)
The default sink cannot be removed, not even with remove_all_sinks. It is used implicitly when no other sinks are added to the core. When you add your sink to the core you automatically suppress the use of the default sink.
As for your problem, could you describe it in more details? A minimal code sample would be useful.
I believe that the corruption was just about flushing buffers correctly, but I can't reproduce it, unfortunately -- I have no problems currently. I found the reason for having to call remove_all_sinks repeatedly : I was initializing multiple logger objects repeatedly, thus adding the sinks to the core multiple times. Unfortunately, I can't avoid this. Is there a better workaround than creating a custom core attribute telling me whether the core has been initialized?
--
I also noticed that the severity filter examples are :
logging::core::get()->set_filter ( logging::trivial::severity >= logging::trivial::info );
From "Setting up sinks", and
sink->set_filter(expr::attr< int >("Severity") >= 2);
(i.e. comparing the Severity with an int) when moving to the more advanced section in "Sink frontends".
Could you adjust one of the examples in "Sink frontends" to use the severity_level type (that the documentation introduces in the tutorial "Adding more information to log: Attributes") directly? For example:
sink->set_filter(expr::attr< severity_level >("Severity") >= sink->warning);
Or explaining this in "Log record formatting".
I had trouble understanding this at first, but I might be the only one :). Thought I'd mention it anyway.
The type of severity level is not mandated by the library, and each section of the documentation is intended to have minimal dependencies on other parts of the library. That's why trivial severity levels are not used in sinks description. I'll think about how to clear this confusion better.
Ok. I understood that the severity_level is allowed to be a custom object. What I did not understand in this context was how to filter the object representing the severity (for trivial::severity it was the object e.g. trivial::fatal, but the advanced documentation compared against an int (I am aware that enums are implicitly casted to ints, but still)). New question: I can't get this (or BOOST_LOG_SCOPED_THREAD_ATTR) to compile: BOOST_LOG_SCOPED_LOGGER_ATTR(_logger, "FID", boost::log::attributes::constant<int>(id)); _logger is a private member reference to a severity_logger Compile errors (more or less equal for BOOST_LOG_SCOPED_THREAD_ATTR): 1>Object.cpp(945): error C2248: 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>::scoped_logger_attribute' : cannot access private member declared in class 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>' 1> with 1> [ 1> LoggerT=boost::log::v2s_mt_nt5::sources::severity_logger<boost::log::v2s_mt_nt5::trivial::severity_level> 1> ] 1> boost/log/attributes/scoped_attribute.hpp(58) : see declaration of 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>::scoped_logger_attribute' 1> with 1> [ 1> LoggerT=boost::log::v2s_mt_nt5::sources::severity_logger<boost::log::v2s_mt_nt5::trivial::severity_level> 1> ]
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Sorry for the delay, I somehow forgot about this email. On Friday 25 January 2013 08:44:01 Mats Taraldsvik wrote:
Hi Andrey,
I found the reason for having to call remove_all_sinks repeatedly : I was initializing multiple logger objects repeatedly, thus adding the sinks to the core multiple times. Unfortunately, I can't avoid this. Is there a better workaround than creating a custom core attribute telling me whether the core has been initialized?
I take it that you are initializing the library while initializing a global logger the first time, is that right? If so, then you probably should move all library initialization code (including addition of sinks and attributes to the core) to an external function and protect it with call_once, once blocks or another similar mechanism. Then you will be able to invoke it multiple times for different global loggers without reinitializing the core.
Ok. I understood that the severity_level is allowed to be a custom object. What I did not understand in this context was how to filter the object representing the severity (for trivial::severity it was the object e.g. trivial::fatal, but the advanced documentation compared against an int (I am aware that enums are implicitly casted to ints, but still)).
The code sample in the sinks description is not related to trivial logging, and actually the filter itself is not important in that example. For clarity, if the filter extracts an int, like in that example, it won't work with other types, so the example assumes that the logger is also using int for severity levels. You can see it in the complete code of the example.
New question:
I can't get this (or BOOST_LOG_SCOPED_THREAD_ATTR) to compile:
BOOST_LOG_SCOPED_LOGGER_ATTR(_logger, "FID", boost::log::attributes::constant<int>(id));
_logger is a private member reference to a severity_logger
Compile errors (more or less equal for BOOST_LOG_SCOPED_THREAD_ATTR):
1>Object.cpp(945): error C2248: 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>::scoped_logg er_attribute' : cannot access private member declared in class 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>' 1> with 1> [ 1> LoggerT=boost::log::v2s_mt_nt5::sources::severity_logger<boost::log::v2s_mt _nt5::trivial::severity_level> 1> ] 1> boost/log/attributes/scoped_attribute.hpp(58) : see declaration of 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>::scoped_logg er_attribute' 1> with 1> [ 1> LoggerT=boost::log::v2s_mt_nt5::sources::severity_logger<boost::log::v2s_mt _nt5::trivial::severity_level> 1> ]
I think I've fixed this in trunk.

Hi Andrey, Sorry for the late reply.
-----Opprinnelig melding----- Fra: Boost [mailto:boost-bounces@lists.boost.org] På vegne av Andrey Semashev Sendt: 27. januar 2013 12:11 Til: boost@lists.boost.org Emne: Re: [boost] [log] v2 Initialisation, default sink behaviour and filtering documentation
Sorry for the delay, I somehow forgot about this email.
On Friday 25 January 2013 08:44:01 Mats Taraldsvik wrote:
Hi Andrey,
I found the reason for having to call remove_all_sinks repeatedly : I was initializing multiple logger objects repeatedly, thus adding the sinks to the core multiple times. Unfortunately, I can't avoid this. Is there a better workaround than creating a custom core attribute telling me whether the core has been initialized?
I take it that you are initializing the library while initializing a global logger the first time, is that right? If so, then you probably should move all library initialization code (including addition of sinks and attributes to the core) to an external function and protect it with call_once, once blocks or another similar mechanism. Then you will be able to invoke it multiple times for different global loggers without reinitializing the core.
Unfortunately, no. I'm implementing a new module called by a legacy interface, and don't know the number of instances of that interface present at a given time (probably, it will be limited to one, but in my test code at least, multiple instances exist). Each interface therefore has its own logger object, and the initialization of this object, along with the initialization of backends/sinks/core, happens at construction of the interface object. Currently I'm calling remove_all_sinks, and this works well. Another approach, that you suggest, would be a static once_flag member for the interface, and call_once for the backends/sink/core initialization. The latter introduces some complexity, and the former is not ideal. I think I'll try to avoid the complexity if the remove_all_sinks approach does not cause any issues..
Ok. I understood that the severity_level is allowed to be a custom object. What I did not understand in this context was how to filter the object representing the severity (for trivial::severity it was the object e.g. trivial::fatal, but the advanced documentation compared against an int (I am aware that enums are implicitly casted to ints, but still)).
The code sample in the sinks description is not related to trivial logging, and actually the filter itself is not important in that example. For clarity, if the filter extracts an int, like in that example, it won't work with other types, so the example assumes that the logger is also using int for severity levels. You can see it in the complete code of the example.
If you could include exactly that paragraph in the docs, when you move from trivial::severity_level to int, that would make things clearer :)
New question:
I can't get this (or BOOST_LOG_SCOPED_THREAD_ATTR) to compile:
BOOST_LOG_SCOPED_LOGGER_ATTR(_logger, "FID", boost::log::attributes::constant<int>(id));
_logger is a private member reference to a severity_logger
Compile errors (more or less equal for BOOST_LOG_SCOPED_THREAD_ATTR):
1>Object.cpp(945): error C2248: 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>::scoped _logg er_attribute' : cannot access private member declared in class 'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>' 1> with 1> [ 1>
LoggerT=boost::log::v2s_mt_nt5::sources::severity_logger<boost::log::v2s_ mt
_nt5::trivial::severity_level> 1> ] 1> boost/log/attributes/scoped_attribute.hpp(58) : see 1> declaration of
'boost::log::v2s_mt_nt5::aux::scoped_logger_attribute<LoggerT>::scoped_lo gg
er_attribute' 1> with 1> [ 1>
LoggerT=boost::log::v2s_mt_nt5::sources::severity_logger<boost::log::v2s_ mt
_nt5::trivial::severity_level> 1> ]
I think I've fixed this in trunk.
Brilliant, thanks! Works very well. :) As a side note, I'm extremely satisfied with the library. Thanks for developing it! :) Regards Mats Taraldsvik
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Friday 08 February 2013 07:53:32 Mats Taraldsvik wrote:
I take it that you are initializing the library while initializing a global logger the first time, is that right? If so, then you probably should move all library initialization code (including addition of sinks and attributes to the core) to an external function and protect it with call_once, once blocks or another similar mechanism. Then you will be able to invoke it multiple times for different global loggers without reinitializing the core.
Unfortunately, no. I'm implementing a new module called by a legacy interface, and don't know the number of instances of that interface present at a given time (probably, it will be limited to one, but in my test code at least, multiple instances exist). Each interface therefore has its own logger object, and the initialization of this object, along with the initialization of backends/sinks/core, happens at construction of the interface object.
Currently I'm calling remove_all_sinks, and this works well. Another approach, that you suggest, would be a static once_flag member for the interface, and call_once for the backends/sink/core initialization. The latter introduces some complexity, and the former is not ideal. I think I'll try to avoid the complexity if the remove_all_sinks approach does not cause any issues..
If you use remove_all_sinks and reinitialize sinks etc. while the other instance of your module is active, it is possible that you lose a few records in the output (they will be fed to the default sink). I think, this was the original issue you mentioned, right? The call_once approach solves this problem.
The code sample in the sinks description is not related to trivial logging, and actually the filter itself is not important in that example. For clarity, if the filter extracts an int, like in that example, it won't work with other types, so the example assumes that the logger is also using int for severity levels. You can see it in the complete code of the example.
If you could include exactly that paragraph in the docs, when you move from trivial::severity_level to int, that would make things clearer :)
Ok, I'll see if I can clarify the docs.
As a side note, I'm extremely satisfied with the library. Thanks for developing it! :)
Thank you for the kind words. :)
participants (2)
-
Andrey Semashev
-
Mats Taraldsvik