Boost log issues and workarounds

Hi, I like the boost log, but there are many small issues, appreciate your kind help: I followed the following link to use a good macro LOG: https://stackoverflow.com/questions/35895199/boost-log-and-severity-local-at... But calling LOG(error) caused much trouble for the name space collision, alternative is to use full namespace boost::log::trivial::error, but that is too cumbersome,I tried to use an uppercase ERROR to replace it in an enum ERROR = boost::log::trivial::error, obviously that could not be complied, although it is defined as enum severity_level in trivial.hpp, it does not look like the boost::log::trivial::error is an enum value. Any workarounds? Another issue from that link is it has to call LOGGABLE prior to call LOG(error) in each function, that makes more clumsy, software developers in my team are not happy about it. Any workaround to have a fixed argument in BOOST_LOG_STREAM_WITH_PARAMS, without need to claim boost::log::sources::severity_logger<boost::log::trivial::severity_level> slg; in each function? You guys are genius that must be a way to do it, appreciate your advice. Thank you

On Thu, 17 Jan 2019 at 10:33, hh h via Boost <boost@lists.boost.org> wrote:
... alternative is to use full namespace boost::log::trivial::error, but that is too cumbersome ...
https://en.cppreference.com/w/cpp/language/namespace_alias degski -- *“If something cannot go on forever, it will stop" - Herbert Stein*

That cannot do namespace INFO = boost::log::trivial::info; so the only way we might run namespace LEVEL = boost::log::trivial; and to call LOG(LEVEL::info), not quite tidy, I am looking into Andrey's solution. Thanks degski

On 18/01/2019 11:23, hh h wrote:
That cannot do namespace INFO = boost::log::trivial::info; so the only way we might run namespace LEVEL = boost::log::trivial; and to call LOG(LEVEL::info), not quite tidy, I am looking into Andrey's solution.
Have you considered: #define LOG_INFO() LOG(boost::log::trivial::info) Or similar.

Thanks, but let me tell you why I tried so hard to get LOG(INFO) working, we used google log before, there are thousands and thousands code lines are using LOG(ERROR), LOG(INFO), it is impossible to change every line of LOG statement to use different LOG name and format. I am keen to use boost log, I have been trying it for weeks, haven't got it work yet, but I don't want to give up until I exhausted all my avenues. Hope I can get there, but hey, thanks your guys for wonderful supports.

On 18/01/2019 12:39, hh h wrote:
Thanks, but let me tell you why I tried so hard to get LOG(INFO) working, we used google log before, there are thousands and thousands code lines are using LOG(ERROR), LOG(INFO), it is impossible to change every line of LOG statement to use different LOG name and format. I am keen to use boost log, I have been trying it for weeks, haven't got it work yet, but I don't want to give up until I exhausted all my avenues. Hope I can get there, but hey, thanks your guys for wonderful supports.
Replace In Files is a thing that exists. Or #define INFO boost::log::trivial::info

Yeah, that was the first thing I tried, but could not compile it, did that work in your site? error: expected ‘}’ before ‘::’ token #define INFO boost::log::trivial::info error: ‘::log’ is not a class, namespace, or enumeration #define INFO boost::log::trivial::info On 1/18/19, Gavin Lambert via Boost <boost@lists.boost.org> wrote:
On 18/01/2019 12:39, hh h wrote:
Thanks, but let me tell you why I tried so hard to get LOG(INFO) working, we used google log before, there are thousands and thousands code lines are using LOG(ERROR), LOG(INFO), it is impossible to change every line of LOG statement to use different LOG name and format. I am keen to use boost log, I have been trying it for weeks, haven't got it work yet, but I don't want to give up until I exhausted all my avenues. Hope I can get there, but hey, thanks your guys for wonderful supports.
Replace In Files is a thing that exists.
Or #define INFO boost::log::trivial::info
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 1/17/19 11:33 AM, hh h via Boost wrote:
Hi,
I like the boost log, but there are many small issues, appreciate your kind help:
I followed the following link to use a good macro LOG:
https://stackoverflow.com/questions/35895199/boost-log-and-severity-local-at...
But calling LOG(error) caused much trouble for the name space collision, alternative is to use full namespace boost::log::trivial::error, but that is too cumbersome,I tried to use an uppercase ERROR to replace it in an enum ERROR = boost::log::trivial::error, obviously that could not be complied, although it is defined as enum severity_level in trivial.hpp, it does not look like the boost::log::trivial::error is an enum value. Any workarounds?
I'm not sure I understand the problem correctly, it would be easier if you described it in more detail, preferably with code samples. From what I gathered, you want a macro `LOG(severity)`, where `severity` is a value from an enum defined by you. First, Boost.Log requires a logger (or, generally speaking, a logging source) to emit log records. You can create either local or global loggers, but since you don't want a logger to be specified in your macro, I'm assuming you want a global logger. See here: https://www.boost.org/doc/libs/1_69_0/libs/log/doc/html/log/detailed/sources... Given a global logger named `my_logger`, your macro could be defined like this: #define LOG(severity) BOOST_LOG_SEV(my_logger::get(), severity) Note that the library provides `BOOST_LOG_TRIVIAL` macro which doesn't require a logger. In this case, a global logger defined by Boost.Log is used. That logger uses `boost::log::trivial::severity_level` enum for its severity levels. Regarding your severity level enum, you have to specify it in template parameters of the logger you use. In the logging macro, you can add any namespaces before the enum value so that the macro expansion context is irrelevant. For example: namespace my_namespace { enum my_severity { verbose, info, error }; } #define LOG(severity) \ BOOST_LOG_SEV(my_logger::get(), ::my_namespace::my_severity::severity) LOG(error) << "Something failed";
Another issue from that link is it has to call LOGGABLE prior to call LOG(error) in each function, that makes more clumsy, software developers in my team are not happy about it. Any workaround to have a fixed argument in BOOST_LOG_STREAM_WITH_PARAMS, without need to claim boost::log::sources::severity_logger<boost::log::trivial::severity_level> slg; in each function? You guys are genius that must be a way to do it, appreciate your advice.
I would say, `LOGGABLE` from one of the linked answers is a library misuse. If you don't have a context associated with the logged activity, you should be using a global logger. Otherwise, you should have a logger specific to the context, e.g. as a class member.

Thank you very much Andrey, that is exactly what I am looking for, does the sample code my_logger.h and my_logger.cpp exist on line or just hypothetical? Thank you and appreciate it.

On 1/17/19 11:37 PM, hh h wrote:
Thank you very much Andrey, that is exactly what I am looking for, does the sample code my_logger.h and my_logger.cpp exist on line or just hypothetical?
Those are just examples in the docs. These particular examples don't exist as standalone files. You can find global loggers used in a number of other examples in the libs/log/example directory.

Hi Andrey,
Those are just examples in the docs. These particular examples don't exist as standalone files. You can find global loggers used in a number of other examples in the libs/log/example directory.
The global loggers is working well, but I could not compile the local log severity, here is the code: BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(my_logger, boost::log::sources::channel_logger_mt< >, (boost::log::keywords::channel = "general")) typedef enum { INFO, DEBUG, WARNING, ERROR, CRITICAL } ServerityLevel_t; template<typename CharT, typename TraitsT> std::basic_ostream< CharT, TraitsT >& operator << (std::basic_ostream< CharT, TraitsT >& strm, ServerityLevel_t lvl) { static const char* const str[] = { "INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL" }; if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str))) { strm << str[lvl]; } else { strm << static_cast< int >(lvl); } return strm; } #define LOG(severity) BOOST_LOG_STREAM_WITH_PARAMS((my_logger::get()), (SetGetAttrib("FileName", PathToFilename(__FILE__)))(SetGetAttrib("LineNumber", (unsigned int)__LINE__))(ServerityLevel_t::severity)) /usr/include/boost/log/sources/channel_feature.hpp:171:60: error: no match for ‘operator[]’ (operand types are ‘const ServerityLevel_t’ and ‘boost::parameter::aux::default_<boost::log::v2_mt_posix::keywords::tag::channel, const boost::parameter::void_>’) return open_record_with_channel_unlocked(args, args[keywords::channel | parameter::void_()]); Obviously, you used BOOST_LOG_SEV where I was using BOOST_LOG_STREAM_WITH_PARAMS, the compiler seems to complain missing operator[], but I have no clue how to define it. Thank you.

Finally fixed it by changing LOG macro (::boost::log::keywords::severity = (ServerityLevel_t::severity). The only thing missing is that in logging::add_file_log( ..." " << boost::log::trivial::severity << ....), that boost::log::trivial::severity is empty, the keyword severity has already been assigned in the macro, what I am missing here? Thanks Andrey.

On 1/18/19 10:27 AM, hh h wrote:
Finally fixed it by changing LOG macro (::boost::log::keywords::severity = (ServerityLevel_t::severity).
The only thing missing is that in logging::add_file_log( ..." " << boost::log::trivial::severity << ....), that boost::log::trivial::severity is empty, the keyword severity has already been assigned in the macro, what I am missing here?
See my other reply. Also, please keep some context of the conversation in your replies.

If you want a severity level attribute, that should be severity_channel_logger_mt< ServerityLevel_t >
I added ServerityLevel_t to the severity_channel_logger_mt, but still couldn't printed out the severity, otherwise, seems everything works.I won't be too worry about the display of severity, finally I can replace the google log by boost log. BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::severity_logger_mt<ServerityLevel_t>) Thank you very much Andrey. On 1/18/19, Andrey Semashev via Boost <boost@lists.boost.org> wrote:
On 1/18/19 10:27 AM, hh h wrote:
Finally fixed it by changing LOG macro (::boost::log::keywords::severity = (ServerityLevel_t::severity).
The only thing missing is that in logging::add_file_log( ..." " << boost::log::trivial::severity << ....), that boost::log::trivial::severity is empty, the keyword severity has already been assigned in the macro, what I am missing here?
See my other reply.
Also, please keep some context of the conversation in your replies.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 1/18/19 12:41 PM, hh h wrote:
If you want a severity level attribute, that should be severity_channel_logger_mt< ServerityLevel_t >
I added ServerityLevel_t to the severity_channel_logger_mt, but still couldn't printed out the severity, otherwise, seems everything works.
If you're using boost::log::trivial::severity keyword in the formatter then that is the problem. This keyword corresponds to the boost::log::trivial::severity_level enum for severity levels. For custom enums, custom keywords should be defined and used. https://www.boost.org/doc/libs/1_69_0/libs/log/doc/html/log/detailed/express... Also, please don't top-post. Our discussion guidelines are described here: https://www.boost.org/community/policy.html

custom keywords should be defined and used.
Thanks Andrey, that fixed the problem. The last issue is to set log level, I tried following statements, neither works: auto filter = boost::log::filter(boost::log::trivial::severity >= ServerityLevel_t::ERROR); boost::log::core::get()->set_filter(filter); OR boost::log::trivial::severity.or_default(ServerityLevel_t::ERROR); What I could be missing? Thank you very much.

On 1/19/19 12:16 AM, hh h wrote:
custom keywords should be defined and used.
Thanks Andrey, that fixed the problem.
The last issue is to set log level, I tried following statements, neither works:
auto filter = boost::log::filter(boost::log::trivial::severity >= ServerityLevel_t::ERROR); boost::log::core::get()->set_filter(filter);
Same as with formatters, you need to use your custom keyword in the filter expression.

Excellent, all done. Thank you so much Andrey, you rock. On 1/19/19, Andrey Semashev via Boost <boost@lists.boost.org> wrote:
On 1/19/19 12:16 AM, hh h wrote:
custom keywords should be defined and used.
Thanks Andrey, that fixed the problem.
The last issue is to set log level, I tried following statements, neither works:
auto filter = boost::log::filter(boost::log::trivial::severity >= ServerityLevel_t::ERROR); boost::log::core::get()->set_filter(filter);
Same as with formatters, you need to use your custom keyword in the filter expression.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hi Andrey, Sorry, I was excited too earlier. In my simple test program, it was working well, but the massive changes of replacing google log by boost log did not go well. That could be due to the complicate real application structure. I have a Log class to wrap the boost log built into a library, the BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT, BOOST_LOG_ATTRIBUTE_KEYWORD and the #define LOG are all defined in Log.hpp, that should be fine, right? The boost log initial function is implemented in the Log class in Log.cpp. The log initial function was called just once in an application base class and remain in the memory until the application exits. First, it got Segmentation fault (core dumped), after changing boost::log::core::get()->add_global_attribute() and boost::log::core::get()->add_thread_attribute() to boost::log::core::get()->add_thread_attribute in the initial function of Log.cpp, it fixed the Segmentation fault, but it did not write anything to the log file in /tmp/log/network.log, the log file is empty. Would you please clarify following questions: (1) Will it be a problem to keep the BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", ::LibraryGlobalServerityLevel_t) and BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(mGlobalLogger, boost::log::sources::severity_logger_mt<::LibraryGlobalServerityLevel_t>) in a header file Log.hpp where many sources include the header file Log.hpp? (2) I think that the boost log initialization should be called once even in multi threading program to share the same log, is it correct? (3) What are different between add_global_attribute and add_thread_attribute? I thought since I use GLOBAL_LOGGER, I should use the add_global_attribute, why it got Segmentation fault? (4) What could I be missing that the log file is empty? I am writing the log file currently to the /tmp which won't cause any permission issues. I tried both static calling boost::log::add_file_log(..) and shared pointer boost::shared_ptr<FileSink_t> sink(new FileSink_t(...) in the log initial function, it did not make any difference, none of it works. (5) Currently I built it using dynamic link, can it use static link? What will be the build macro for static link?

Hi Andrey, I found the cause that the log file was empty, after calling in LOG(INFO), it needs to call flush() to see the message in log file. Appreciate if you could clarify other questions (except 4). Thank you very much.

On 1/20/19 10:36 AM, hh h via Boost wrote:
Would you please clarify following questions:
(1) Will it be a problem to keep the BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", ::LibraryGlobalServerityLevel_t) and BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(mGlobalLogger, boost::log::sources::severity_logger_mt<::LibraryGlobalServerityLevel_t>) in a header file Log.hpp where many sources include the header file Log.hpp?
No, it shouldn't be a problem.
(2) I think that the boost log initialization should be called once even in multi threading program to share the same log, is it correct?
Yes. Logging initialization should be performed once, early when the application starts.
(3) What are different between add_global_attribute and add_thread_attribute? I thought since I use GLOBAL_LOGGER, I should use the add_global_attribute, why it got Segmentation fault?
These are different kinds of attributes. https://www.boost.org/doc/libs/1_69_0/libs/log/doc/html/log/design.html#log.... What kind of logger you are using is irrelevant to the kind of attributes you use. I can't tell the cause of the crash without a backtrace and a source code.
(4) What could I be missing that the log file is empty? I am writing the log file currently to the /tmp which won't cause any permission issues. I tried both static calling boost::log::add_file_log(..) and shared pointer boost::shared_ptr<FileSink_t> sink(new FileSink_t(...) in the log initial function, it did not make any difference, none of it works.
Since you said that flushing makes the log records appear in the file, this is probably due to buffering in the file stream. I'm assuming you're not using async logging, otherise it could also be buffering in the sink frontend. To avoid buffering in the file stream you can enable auto flush in the sink backend. This will reduce performance, though.
(5) Currently I built it using dynamic link, can it use static link? What will be the build macro for static link?
You can only use static linking if you use Boost.Log from a single module of your application. https://www.boost.org/doc/libs/1_69_0/libs/log/doc/html/log/installation/con...

I'm assuming you're not using async logging
I am using synchronous so I can keep the order of log messages for debugging.
To avoid buffering in the file stream you can enable auto flush in the sink backend.
Actually I like controlling the auto flush manually as I am running on the embedded system, I can prolong the flash storage lifetime. Stability is the absolute goal. Thank you very much Andrey.

On 1/18/19 6:45 AM, hh h wrote:
Hi Andrey,
Those are just examples in the docs. These particular examples don't exist as standalone files. You can find global loggers used in a number of other examples in the libs/log/example directory.
The global loggers is working well, but I could not compile the local log severity, here is the code:
BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(my_logger, boost::log::sources::channel_logger_mt< >, (boost::log::keywords::channel = "general"))
If you want a severity level attribute, that should be severity_channel_logger_mt< ServerityLevel_t >.
typedef enum { INFO, DEBUG, WARNING, ERROR, CRITICAL } ServerityLevel_t;
template<typename CharT, typename TraitsT> std::basic_ostream< CharT, TraitsT >& operator << (std::basic_ostream< CharT, TraitsT >& strm, ServerityLevel_t lvl) { static const char* const str[] = { "INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL" }; if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str))) { strm << str[lvl]; } else { strm << static_cast< int >(lvl); } return strm; }
#define LOG(severity) BOOST_LOG_STREAM_WITH_PARAMS((my_logger::get()), (SetGetAttrib("FileName", PathToFilename(__FILE__)))(SetGetAttrib("LineNumber", (unsigned int)__LINE__))(ServerityLevel_t::severity))
/usr/include/boost/log/sources/channel_feature.hpp:171:60: error: no match for ‘operator[]’ (operand types are ‘const ServerityLevel_t’ and ‘boost::parameter::aux::default_<boost::log::v2_mt_posix::keywords::tag::channel, const boost::parameter::void_>’) return open_record_with_channel_unlocked(args, args[keywords::channel | parameter::void_()]);
I'm not sure what SetGetAttrib is, but BOOST_LOG_STREAM_WITH_PARAMS assumes the parameters are Boost.Parameter named parameters. I.e. to pass a severity level you need to say: (::boost::log::keywords::severity = ServerityLevel_t::severity) and to pass a channel name: (::boost::log::keywords::channel = (chan)) If you want to use named parameters to add FileName and LineNumber attributes, you will have to write your own logger feature and add it to the severity level and channel features, as described here: https://www.boost.org/doc/libs/1_69_0/libs/log/doc/html/log/extension/source... If you don't need to apply filters to these attributes, you can just use add_value manipulator in your macro: https://www.boost.org/doc/libs/1_69_0/libs/log/doc/html/log/detailed/utiliti... That will work without having to develop a new logger feature.
participants (4)
-
Andrey Semashev
-
degski
-
Gavin Lambert
-
hh h