LINUX.ORG.RU

Boost.Log

 ,


0

2

Как в basic_sink_backend в реализации функции

    void consume(const boost::log::record_view& rec)
    {
    }

вытащить значение severity level для rec? Само сообщение как-то примерно так через задницу достается:

*rec[boost::log::expressions::smessage]
Но не severity level. Вообще, просто зла не хватает на автора этого Boost.Log. Марсианин какой-то. Сплошная, блин, гибкость кругом, только воспользоваться ничем нельзя и документация кривая. В документации одни неймспейсы, в коде - другие, и ничего толком не описано. Самая основная вещь и хрен чего про неё найдешь.

★★★★★

Последнее исправление: asaw (всего исправлений: 1)

сделал так:

        auto map = rec.attribute_values();
        for(auto mi = map.begin(); mi != map.end(); ++mi) {
            std::clog << mi->first << " : " << mi->second.get_type().pretty_name() << std::endl;
        }

Получил на выходе:

Severity : [uninitialized]
Message : std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >

ну и как, блин, таким пользоваться?? facepalm.jpg

asaw ★★★★★
() автор топика

ну, гуголь вывел на вот это:
http://stackoverflow.com/questions/17491561/boost-log-callback
там в первом же ответе приведён, кхм, примерчик...
не, это действительно изврат. если ты не из ЛГБИ, то лучше в это не лезть. что за плюсы должны быть у этого монстра, чтобы окупить моральные издержки на такой извращённый синтаксис?

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

Ну так boost::log::aux::default_attribute_names::severity() это и есть тот самый атрибут Severity который [uninitialized]. Не работает оно. Потому я и спрашиваю. В лог пишу с помощью BOOST_LOG_TRIVIAL, который severety_logger. Всё должно работать, а оно не работает.

asaw ★★★★★
() автор топика

Сделал примерчик: http://rextester.com/XKQ95959

// c++ -Wall -std=c++11 -O2 -DBOOST_LOG_DYN_LINK -I /opt/local/include -L /opt/local/lib -o a.out crap14.cc -lboost_log-mt -lboost_system-mt -lpthread

#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/sinks/frontend_requirements.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/trivial.hpp>
#include <iostream>

class ForwardingLogSinkBackend : public boost::log::sinks::basic_sink_backend<boost::log::sinks::combine_requirements<boost::log::sinks::synchronized_feeding>::type> {
public:
    explicit ForwardingLogSinkBackend()
    {
    }

    // The function consumes the log records that come from the the logging frontend
    void consume(const boost::log::record_view& rec)
    {
        auto map = rec.attribute_values();
        for(auto mi = map.begin(); mi != map.end(); ++mi) {
            std::clog << mi->first << " : " << mi->second.get_type().pretty_name() << std::endl;
        }

        auto severity = rec.attribute_values()[boost::log::aux::default_attribute_names::severity()].extract<boost::log::trivial::severity_level>();
        std::clog << "severity" << " = " << severity << ", message = " << *rec[boost::log::expressions::smessage] << std::endl;
    }

};

typedef boost::log::sinks::synchronous_sink<ForwardingLogSinkBackend> ForwardingLogSink;


int main()
{
    auto sink = boost::make_shared<ForwardingLogSink>(boost::make_shared<ForwardingLogSinkBackend>());
    boost::log::core::get()->add_sink(sink);

    BOOST_LOG_TRIVIAL(info) << "Hello, World!";
}

Там, хоть и через задницу, но работает. У меня тот же код, но вызываемый внутри динамической библиотеки, уже выдает что-то вроде severity = , message = Hello, World!

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

у меня как-то проще получилось:

#include <string>
#include <boost/log/trivial.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/attributes/value_extraction.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
using namespace std;
namespace sinks = boost::log::sinks;

struct Sink: public sinks::basic_formatted_sink_backend<char, sinks::concurrent_feeding> {
void consume (const boost::log::record_view& rec, const string& str) {
  using boost::log::trivial::severity_level;
  auto severity = rec.attribute_values()[boost::log::aux::default_attribute_names::severity()].extract<severity_level>();
  if(severity) {
        cout << severity.get() << endl;
      if (severity.get() <= severity_level::info) {
        cout << "info:" << str << endl;
      } else {
        cout << "error:" << str << endl;
    }
  }
}
};

int main() {
  typedef sinks::synchronous_sink<Sink> sink_t;
  boost::shared_ptr<sink_t> sink (new sink_t());
  boost::shared_ptr<boost::log::core> logc = boost::log::core::get();
  logc->add_sink (sink);

  BOOST_LOG_TRIVIAL(error) << "An error severity message";
  BOOST_LOG_TRIVIAL(info) << "An info severity message";
}

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

Проще - это использовать оператор [] напрямую у rec, а не просить attribute_values(), а так нет принципиальной разницы. Проблема в том, что если этот sink положить в DLL и logc->add_sink (sink); делать оттуда же, то при вызове severity.get() будет вот как-то так:

Assertion failed: (m_ptr != __null), function get, file /opt/local/include/boost/log/utility/value_ref.hpp, line 150.
Abort trap: 6

ЗЫ кстати твой Sink - никакой не sink на самом деле, а именно sink backend. И у меня он от basic_sink_backend наследуется, что тоже имеет значение.

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

ну, во-первых, я не телепат, чужие мысли на расстоянии улавливаю плохо. во-вторых, я этот boost::log после прочтения этой темы в первый раз вижу. boost'ом вообще пользуюсь много лет, версии так с 29-й. но не всё отслеживаю, да и не всё мне нужно в работе. думаю, если поковыряться больше 15 минут, то можно понять, какая там идеология. хотя синтаксис библиотеки удрочает весьма, это факт.

Iron_Bug ★★★★★
()
Ответ на: комментарий от asaw

хм. выношу всё в dll. всё равно работает.
код dll:

#include <string>
#include <boost/log/trivial.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/attributes/value_extraction.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
using namespace std;
namespace sinks = boost::log::sinks;

extern "C" void init();

int main() {
  init();
  
  BOOST_LOG_TRIVIAL(error) << "An error severity message";
  BOOST_LOG_TRIVIAL(info) << "An info severity message";
}

код вызывающей программы:
#include <string>
#include <boost/log/trivial.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/attributes/value_extraction.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
using namespace std;
namespace sinks = boost::log::sinks;

struct Sink: public sinks::basic_formatted_sink_backend<char, sinks::concurrent_feeding> {
void consume (const boost::log::record_view& rec, const string& str) {
  using boost::log::trivial::severity_level;
  auto severity = rec.attribute_values()[boost::log::aux::default_attribute_names::severity()].extract<severity_level>();
  if(severity) {
        cout << severity.get() << endl;
      if (severity.get() <= severity_level::info) {
        cout << "info:" << str << endl;
      } else {
        cout << "error:" << str << endl;
    }
  }
}
};


extern "C"
{
    void init()
    {
        typedef sinks::synchronous_sink<Sink> sink_t;
        boost::shared_ptr<sink_t> sink (new sink_t());
        boost::shared_ptr<boost::log::core> logc = boost::log::core::get();
        logc->add_sink (sink);
    }
}

код не претендует на оптимальность ни в коей мере. это просто грязный хак задней левой ногой, чисто ради проверки. и всё работает как надо.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

то есть, код наеборот. вверху - программа, внизу - dll. ну, это и так понятно.

Iron_Bug ★★★★★
()

Вообще, просто зла не хватает на автора этого Boost.*. Марсианин какой-то. Сплошная, блин, гибкость кругом, только воспользоваться ничем нельзя и документация кривая. В документации одни неймспейсы, в коде - другие, и ничего толком не описано. Самая основная вещь и хрен чего про неё найдешь.

Вот да, в этом почти весь буст

yoghurt ★★★★★
()
Ответ на: комментарий от Iron_Bug

А если в библиотеке BOOST_LOG_TRIVIAL() вызвать - тоже работает? Ну понятно, что такие штуки уже сильно зависят от компилятора, параметров линковки и т.п.

asaw ★★★★★
() автор топика
Ответ на: комментарий от yoghurt

Ну я бы не сказал так про весь boost. Из того, чем я там успел попользоваться (не считая того, что уже переехало стандартную библиотеку) - unit_test_framework, program_options, filesystem, system, thread, serialization, endian, chrono, log - у log самый идиотский интерфейс (и вообще архитектура). Далее за ним идет program_options, но там уже лучше. Кстати, характерно, что авторы этих двух библиотек - выходцы из СССР. Закономерность?

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

Далее за ним идет program_options

А с ним-то что не так? По моему, всё нормально.

А вот лог и правда получился «странный». Посматривал на либу ещё до принятия в буст - всё-таки иметь стандартное логирование удобно. Надеялся, что раз сразу не приняли, то автор более прямо сделает, но похоже не судьба.

DarkEld3r ★★★★★
()
Ответ на: комментарий от asaw

асболютно без проблем. я тут не вижу никаких зависимостей от того, где эту фигню инициализировать. библиотека подгружается и дальше работает в том же пространстве памяти. никаких хитростей тут нет. компилятор у меня совершенно стандартный GCC 4.9.2. параметры компиляции тоже стандартные для подобных вещей:
-std=c++11 -Wall -fexceptions -pthread -fPIC -DBOOST_LOG_DYN_LINK
ничего такого особенного.

Iron_Bug ★★★★★
()
Ответ на: комментарий от asaw

да, кстати, program_options у меня использовался в некоторых проектах и мне он показался довольно удобным. у меня была железяка, в которую прогружалось более 200 параметров и чтобы весь этот зоопарк как-то консистентно представить для юзера, был заюзан boost::program_options. на него у меня нареканий нет. он довольно просто и свои задачи вполне решает.
я тоже «выходец из СССР». и это во многом мне помогло. у меня хотя бы образование хорошее.

Iron_Bug ★★★★★
()
Ответ на: комментарий от DarkEld3r

А с ним-то что не так? По моему, всё нормально.

Да тоже накручено всего, но при этом на сами опции приходится ссылаться по их строковым названиям. В результате можно ссылаться на несуществующие опции и не знать об этом до тех пор, пока в рантайме этот баг не вылезет. У boost::program_options::notify() странная семантика с выбросом исключения. Документация тоже не ахти. Потом, в С++11 есть статическая инициализация, там её до сих пор не появилось. Ну а так то лучше, чем log, конечно.

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

да куда эта статическая инициализация упёрлась? без неё жили сто лет, никто не жужжал. буст - это обкатка будущих стандартов С++. но у них нет цели ежедневно обновлять весь свой код, которого там немало. они в первую очередь поддерживают консистентность на всех платформах и компиляторах, которые буст поддерживает.
я считаю, что программист должен думать головой. а не надеяться, что компилятор его спасёт от него самого. ошибки типа «ссылался на несуществующую опцию» из разряда ССЗБ. обычно системы и библиотеки предоставляют интерфейсы для проверки того, существует ли объект, можно ли писать в какой-то адрес и многое другое. вопрос лишь в том, насколько программист дисциплинирован, чтобы использовать эти проверки.

Iron_Bug ★★★★★
()
Ответ на: комментарий от asaw

но при этом на сами опции приходится ссылаться по их строковым названиям

Это всё-таки не всегда надо. Да и как бы ты сделал?

У boost::program_options::notify() странная семантика с выбросом исключения

Что именно не нравится?

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Не нравится, что в документации http://www.boost.org/doc/libs/1_58_0/doc/html/boost/program_options/notify.html всего одна строка - Runs all 'notify' function for options in 'm'. А на самом деле эта штуковина первым и главным делом проверит m и выбросит исключение, если там будет что-то не так (какой-нибудь обязательной опции например нет). То есть проверка неявная, да ещё и недокументированная.

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

Unit test framework по сравнению с гугл тест как... Ну я не знаю даже. На буст-эксепшон еще глянь. Не, он Клевый конечно, но странный.

yoghurt ★★★★★
()

В итоге, несмотря на обилие библиотек из boost в проекте, переехал с boost.log на spdlog: https://github.com/gabime/spdlog Библиотечка на порядок проще и на 2 порядка быстрее, что тоже важно.

С Boost.Log не стал разбираться дальше поскольку:

If your application consists of more than one module (e.g. an exe and one or several dll's) that use Boost.Log, the library must be built as a shared object. If you have a single executable or a single module that works with Boost.Log, you may build the library as a static library.

и хотя в конкретном описанном случае линковка с boost.log была динамической (и всё равно не работало!), на винде проект линкуется статически. Spdlog с этой ситуацией справляется нормально. Единственная проблема - при использовании синглетонов на статических переменных, при попытке использовать spdlog из деструктора такого синглетона, spdlog начинает кидать исключения (ибо сам реализован на таких синглетонах), что, в общем, предсказуемо.

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

не, ну требование динамики при использовании из разных модулей - оно понятно и это вполне ожидаемо. но под офтопиком нет проблем собрать динамику. буст даже в уже собранном виде поставляется под маздай. просто синтаксис библиотеки не особо удобен. а если она ещё и тормозит, то и вовсе нет смысла её юзать.

Iron_Bug ★★★★★
()
Ответ на: комментарий от DELIRIUM

Потому что header-only, да и вообще C++11. Поскольку есть возможность использовать новое - использую.

asaw ★★★★★
() автор топика
Ответ на: комментарий от Iron_Bug

но под офтопиком нет проблем собрать динамику.

Проблем нет, но есть нефункциональные требования)

asaw ★★★★★
() автор топика
29 ноября 2015 г.
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.