Я не знаю ни одного фреймворка для ведения журнала, но я играл на достаточно симпатичном принтере, так что я знаю, что это не очень сложно.
Предположим, существует класс Logger, который поддерживает push
иpop
операций:
class LogNester: private boost::noncopyable {
public:
LogNester(Logger& l): logger(l) { logger.push(); }
~LogNester() { logger.pop(); }
private:
Logger& logger;
};
Использование:
void foo() {
LogNester _(GlobalLogger);
// do something
}
Важный момент one : вам необходимо имя переменной, LogNester(GlobalLogger)
будет выдвигать и выдвигать только это утверждение (upps), тогда как именованная переменная будет жить до конца области действия.
Если вам надоело каждый раз придумывать новые имена (что я могу понять), вы всегда можете прибегнуть к макросу:
#define NESTLOG() LogNester BOOST_PP_CAT(log, __LINE__)(GlobalLogger);
Тем не менее, он не совсем ... автоматизирован, так как вам нужно определить LogNester
объект при входе для каждого метода.Теоретически, вы должны быть в состоянии волшебно получить глубину, если не возражаете немного замедлить: использование информации о вызовах стека.С gcc
это делается с помощью утилиты backtrace
:
#include <execinfo.h> // GNU/Linux specific header
inline unsigned depth() {
void* Stack[64];
return backtrace(Stack, sizeof(Stack));
}
Затем улучшите макрос ведения журнала:
#define LOG(Message_) \
do { \
GlobalLogger.log(__FILE__, __LINE__, __FUNCTION__, depth(), Message_); \
} while(0)
Конечно, это очень зависит от того, являются ли вызовы встроеннымиили нет.
Я лично обнаружил, что __FILE__
, __LINE__
и __FUNCTION__
было достаточно для моих нужд.