Включить Boost.Log только при отладке

Мне нужен регистратор для отладки, и я использую Boost.Log (1.54.0 с патчем на домашней странице boost.org).

Все в порядке, я создал такой макрос:

#define LOG_MESSAGE( lvl ) BOOST_LOG_TRIVIAL( lvl )

Таким образом, LOG_MESSAGE(lvl) раскрывается в BOOST_LOG_TRIVIAL(lvl) только в режиме отладки и игнорируется в релизе?

Например:

LOG_MESSAGE( critical ) << "If I read this message we're in debug mode"

edit Моя первая попытка - создать нулевой поток... Я думаю, что компилятор в режиме выпуска оптимизирует его...

#if !defined( NDEBUG )
#include <boost/log/trivial.hpp>
#define LOG_MESSAGE( lvl ) BOOST_LOG_TRIVIAL( lvl )
#else
#if defined( __GNUC__ )
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-value"
#endif


#include <iosfwd>
struct nullstream : public std::ostream {
    nullstream() : std::ios(0), std::ostream(0) {}
};

static nullstream g_nullstream;

#define LOG_MESSAGE( lvl ) g_nullstream

#if defined( __GNUC__ )
#pragma GCC diagnostic pop
#endif

#endif

person Elvis Dukaj    schedule 11.07.2013    source источник


Ответы (3)


Уровень серьезности записи в журнале просто действует как фильтр для приемников. Приемник решит, что делать с сообщением (печатать его или нет) в зависимости от уровня серьезности. Но сообщение все равно будет отправлено.

Если вы пытаетесь не отправлять сообщение вообще, вам нужно переопределить LOG_MESSAGE на что-то, что на самом деле ничего не делает. в библиотеке Boost может быть что-то для этого, в противном случае вам придется писать свой собственный. Возможно, это будет началом:

class NullLogger
{
public:
  template <typename SeverityT> NullLogger (SeverityT) {};
  template <typename Val> NullLog& operator<< (const Val&) { return * this};
};

...а потом:

#define LOG_MESSAGE (lvl) NullLogger (lvl)

Однако обратите внимание, что даже если с сообщением журнала или составляющими его выражениями ничего не делается, выражения все равно оцениваются. Если некоторые из этих выражений являются дорогостоящими, вы все равно получите удар по производительности. Например:

LOG_MESSAGE (debug) << SomeSuperExpensiveFunction();

Даже если вы используете NullLogger выше, SomeSuperExpensiveFunction() все равно будет вызываться.

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

if (mLogStuff)
{ 
  LOG_MESSAGE (debug) << SomeSuperExpensiveFunction();
}

boolean сравнения очень дешевы, и однажды в будущем вы можете обнаружить, что возможность включать и выключать регистрацию может быть очень удобной. Кроме того, это означает, что вам не нужно добавлять еще один #define, что всегда хорошо.

person John Dibling    schedule 11.07.2013

Мне нравится NullLogger класс Джона. Единственное изменение, которое я бы сделал, заключается в следующем

#define LOG_MESSAGE(lvl) while (0) NullLogger (lvl)

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

person Stephen Nutt    schedule 03.08.2013
comment
Этот метод вряд ли полезен. Это может предотвратить вызов методов NullLogger, но посмотрите на них: они определены в классе, поэтому inline. Они тоже пустые. Вызывать их только теоретически, на практике оптимизатор удалит все следы NullLogger. - person MSalters; 04.08.2017

Класс Джона NullLogger неправильно компилируется в MSVC и по-прежнему требует зависимости Boost для SeverityT, которая на самом деле не нужна.

Я предлагаю следующее изменение в классе:

class NullLogger
{
    public:
        template <typename Val> NullLogger& operator<< (const Val&) { return *this; };
};
#define BOOST_LOG_TRIVIAL(lvl) NullLogger()
person Enrico Detoma    schedule 17.03.2021