Включение имени потока в лог буста - PullRequest
0 голосов
/ 01 апреля 2020

Используя журнал буста, я включаю идентификатор потока в сообщения журнала.

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
             ^

Есть предложения?

Ответы [ 2 ]

2 голосов
/ 01 апреля 2020

Начиная с примера в документации упрощает реализацию.

#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;
}
0 голосов
/ 02 апреля 2020

Я использую макрос, определенный в моем заголовочном файле лог-буста, который вызывается из самой функции:

#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();

Я задал этот же вопрос, более или менее, четыре года go: добавить файл, функцию, строку в глобальный регистратор повышения .

...