在 boost 日志中包含线程名称
Including thread name in boost log
使用 boost 日志,我在日志消息中包含了线程 ID。
sink->set_formatter(
expr::stream
<< /* other attributes */ <<
<< expr::attr<bboost::log::attributes::current_thread_id::value_type>(
"ThreadID")
<< expr::smessage);
然而,这很麻烦,因为肉眼很难区分哪些消息来自哪个线程。
2020-Apr-01 14:50:44.901416 info[pliny.cc:900/0x00007f4428f81780] Change epistula processing complete.
2020-Apr-01 14:50:44.901686 debug[pliny.cc:852/0x00007f441d3ec700] Worker starting task from idle: ...
我想使用 pthread_setname_np
/pthread_getname_np
在日志中打印线程的名称。我将 boost/log/attributes/current_thread_id.hpp
复制到一个名为 current_thread_name.h
的文件并对其进行了修改,希望能打印线程的名称。 (目前我只是想打印常量字符串 "x"。一次一个。)
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
#include <boost/log/attributes/attribute_value_impl.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/detail/header.hpp>
#include <boost/log/detail/thread_id.hpp>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <string>
#if defined(BOOST_LOG_NO_THREADS)
#error Boost.Log: The current_thread_name attribute is only available in multithreaded builds
#endif
typedef boost::log::aux::id<std::string> thread_name;
class current_thread_name : public boost::log::attribute {
public:
typedef thread_name value_type;
protected:
class BOOST_SYMBOL_VISIBLE impl : public boost::log::attribute_value::impl {
public:
bool dispatch(boost::log::type_dispatcher& dispatcher) {
boost::log::type_dispatcher::callback<value_type> callback =
dispatcher.get_callback<value_type>();
if (callback) {
callback([]() { return boost::log::aux::id<std::string>(std::string("x")); }());
return true;
} else
return false;
}
boost::intrusive_ptr<boost::log::attribute_value::impl>
detach_from_thread() {
typedef boost::log::attributes::attribute_value_impl<value_type>
detached_value;
return new detached_value(boost::log::aux::this_thread::get_id());
}
boost::log::type_info_wrapper get_type() const {
return boost::log::type_info_wrapper(typeid(value_type));
}
};
public:
current_thread_name() : attribute(new impl()) {}
explicit current_thread_name(
boost::log::attributes::cast_source const& source)
: attribute(source.as<impl>()) {}
};
#include <boost/log/detail/footer.hpp>
遗憾的是,我没有看到如何在回调中获得正确的类型。
/usr/include/boost/log/detail/id.hpp:38:35: error: no type named 'native_type' in
'std::__cxx11::basic_string<char>'
typedef typename DescriptorT::native_type native_type;
~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
src/current_thread_name.h:66:40: note: in instantiation of template class
'boost::log::v2_mt_posix::aux::id<std::__cxx11::basic_string<char> >' requested here
callback([]() { return boost::log::aux::id<std::string>(std::string("x")); }());
^
src/current_thread_name.h:66:17: error: no matching function for call to object of type
'boost::log::type_dispatcher::callback<value_type>' (aka 'callback<id<basic_string<char> > >')
callback([]() { return boost::log::aux::id<std::string>(std::string("x")); }());
^~~~~~~~
/usr/include/boost/log/utility/type_dispatch/type_dispatcher.hpp:102:14: note: candidate function not
viable: cannot convert argument of incomplete type 'void' to 'const
boost::log::v2_mt_posix::aux::id<std::__cxx11::basic_string<char> >'
void operator() (T const& value) const
^
有什么建议吗?
从 documentation 中的示例开始可以使实现更简单。
#include <string>
#include <boost/log/core.hpp>
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_value.hpp>
#include <boost/log/attributes/attribute_value_impl.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
thread_local std::string threadName;
class thread_name_impl :
public boost::log::attribute::impl
{
public:
boost::log::attribute_value get_value()
{
return boost::log::attributes::make_attribute_value(threadName.empty() ? std::string("no name") : threadName);
}
};
class thread_name :
public boost::log::attribute
{
public:
thread_name() : boost::log::attribute(new thread_name_impl())
{
}
explicit thread_name(boost::log::attributes::cast_source const& source) : boost::log::attribute(source.as< thread_name_impl >())
{
}
};
我使用 thread_local std::string threadName
而不是 pthread
来使代码跨平台。您可以通过简单地分配给 threadName
变量来设置线程名称,例如:
threadName = "main";
修改此示例以使用 pthread
应该相当容易。
使用示例:
#include <iostream>
#include <thread>
#include <stdexcept>
#include <boost/config.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/core/null_deleter.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
void init_logging()
{
boost::shared_ptr< boost::log::core > core = boost::log::core::get();
typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_ostream_backend > sink_t;
boost::shared_ptr< sink_t > sink(new sink_t());
sink->locked_backend()->add_stream(boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter()));
sink->set_formatter(boost::log::expressions::stream << boost::log::expressions::attr< std::string >("ThreadName") << ": " << boost::log::expressions::smessage);
core->add_sink(sink);
core->add_global_attribute("ThreadName", thread_name());
}
int main(int, char*[])
{
init_logging();
threadName = "main";
boost::log::sources::logger lg;
std::thread thread([&lg] {
threadName = "worker";
BOOST_LOG(lg) << "worker thread";
});
BOOST_LOG(lg) << "main thread";
thread.join();
return 0;
}
我使用从函数本身调用的 boost 日志记录头文件中定义的宏:
#define INFO BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::info) << "[" << __FILENAME__ << "/" << __FUNCTION__ << ":" << __LINE__ << "] "
从函数调用的宏:
INFO << "thread started >> thread ID = " << boost::this_thread::get_id();
四年前我或多或少问过同样的问题:。
使用 boost 日志,我在日志消息中包含了线程 ID。
sink->set_formatter(
expr::stream
<< /* other attributes */ <<
<< expr::attr<bboost::log::attributes::current_thread_id::value_type>(
"ThreadID")
<< expr::smessage);
然而,这很麻烦,因为肉眼很难区分哪些消息来自哪个线程。
2020-Apr-01 14:50:44.901416 info[pliny.cc:900/0x00007f4428f81780] Change epistula processing complete.
2020-Apr-01 14:50:44.901686 debug[pliny.cc:852/0x00007f441d3ec700] Worker starting task from idle: ...
我想使用 pthread_setname_np
/pthread_getname_np
在日志中打印线程的名称。我将 boost/log/attributes/current_thread_id.hpp
复制到一个名为 current_thread_name.h
的文件并对其进行了修改,希望能打印线程的名称。 (目前我只是想打印常量字符串 "x"。一次一个。)
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
#include <boost/log/attributes/attribute_value_impl.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/detail/header.hpp>
#include <boost/log/detail/thread_id.hpp>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <string>
#if defined(BOOST_LOG_NO_THREADS)
#error Boost.Log: The current_thread_name attribute is only available in multithreaded builds
#endif
typedef boost::log::aux::id<std::string> thread_name;
class current_thread_name : public boost::log::attribute {
public:
typedef thread_name value_type;
protected:
class BOOST_SYMBOL_VISIBLE impl : public boost::log::attribute_value::impl {
public:
bool dispatch(boost::log::type_dispatcher& dispatcher) {
boost::log::type_dispatcher::callback<value_type> callback =
dispatcher.get_callback<value_type>();
if (callback) {
callback([]() { return boost::log::aux::id<std::string>(std::string("x")); }());
return true;
} else
return false;
}
boost::intrusive_ptr<boost::log::attribute_value::impl>
detach_from_thread() {
typedef boost::log::attributes::attribute_value_impl<value_type>
detached_value;
return new detached_value(boost::log::aux::this_thread::get_id());
}
boost::log::type_info_wrapper get_type() const {
return boost::log::type_info_wrapper(typeid(value_type));
}
};
public:
current_thread_name() : attribute(new impl()) {}
explicit current_thread_name(
boost::log::attributes::cast_source const& source)
: attribute(source.as<impl>()) {}
};
#include <boost/log/detail/footer.hpp>
遗憾的是,我没有看到如何在回调中获得正确的类型。
/usr/include/boost/log/detail/id.hpp:38:35: error: no type named 'native_type' in
'std::__cxx11::basic_string<char>'
typedef typename DescriptorT::native_type native_type;
~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
src/current_thread_name.h:66:40: note: in instantiation of template class
'boost::log::v2_mt_posix::aux::id<std::__cxx11::basic_string<char> >' requested here
callback([]() { return boost::log::aux::id<std::string>(std::string("x")); }());
^
src/current_thread_name.h:66:17: error: no matching function for call to object of type
'boost::log::type_dispatcher::callback<value_type>' (aka 'callback<id<basic_string<char> > >')
callback([]() { return boost::log::aux::id<std::string>(std::string("x")); }());
^~~~~~~~
/usr/include/boost/log/utility/type_dispatch/type_dispatcher.hpp:102:14: note: candidate function not
viable: cannot convert argument of incomplete type 'void' to 'const
boost::log::v2_mt_posix::aux::id<std::__cxx11::basic_string<char> >'
void operator() (T const& value) const
^
有什么建议吗?
从 documentation 中的示例开始可以使实现更简单。
#include <string>
#include <boost/log/core.hpp>
#include <boost/log/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_value.hpp>
#include <boost/log/attributes/attribute_value_impl.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
thread_local std::string threadName;
class thread_name_impl :
public boost::log::attribute::impl
{
public:
boost::log::attribute_value get_value()
{
return boost::log::attributes::make_attribute_value(threadName.empty() ? std::string("no name") : threadName);
}
};
class thread_name :
public boost::log::attribute
{
public:
thread_name() : boost::log::attribute(new thread_name_impl())
{
}
explicit thread_name(boost::log::attributes::cast_source const& source) : boost::log::attribute(source.as< thread_name_impl >())
{
}
};
我使用 thread_local std::string threadName
而不是 pthread
来使代码跨平台。您可以通过简单地分配给 threadName
变量来设置线程名称,例如:
threadName = "main";
修改此示例以使用 pthread
应该相当容易。
使用示例:
#include <iostream>
#include <thread>
#include <stdexcept>
#include <boost/config.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/core/null_deleter.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
void init_logging()
{
boost::shared_ptr< boost::log::core > core = boost::log::core::get();
typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_ostream_backend > sink_t;
boost::shared_ptr< sink_t > sink(new sink_t());
sink->locked_backend()->add_stream(boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter()));
sink->set_formatter(boost::log::expressions::stream << boost::log::expressions::attr< std::string >("ThreadName") << ": " << boost::log::expressions::smessage);
core->add_sink(sink);
core->add_global_attribute("ThreadName", thread_name());
}
int main(int, char*[])
{
init_logging();
threadName = "main";
boost::log::sources::logger lg;
std::thread thread([&lg] {
threadName = "worker";
BOOST_LOG(lg) << "worker thread";
});
BOOST_LOG(lg) << "main thread";
thread.join();
return 0;
}
我使用从函数本身调用的 boost 日志记录头文件中定义的宏:
#define INFO BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::info) << "[" << __FILENAME__ << "/" << __FUNCTION__ << ":" << __LINE__ << "] "
从函数调用的宏:
INFO << "thread started >> thread ID = " << boost::this_thread::get_id();
四年前我或多或少问过同样的问题: