Как реализовать хорошую функцию отладки / регистрации в проекте - PullRequest
14 голосов
/ 29 мая 2011

Я делаю небольшой проект, всего около 3-4 человек. Я хочу иметь надежный способ отладки приложения, например, по журналам. Есть ли хорошие ресурсы о том, как его структурировать и тому подобное? От руководителей проектов я много слышал, что хорошая функция ведения журналов имеет решающее значение для каждого проекта, но я не уверен, как это сделать.

Ответы [ 3 ]

16 голосов
/ 29 мая 2011

Я нашел эту статью доктора Добба, Вход в систему C ++ , очень полезную в этом вопросе.

Также на Dr. Dobb's: Высококонфигурируемая среда ведения журналов в C ++

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

#ifndef _LOGGER_HPP_
#define _LOGGER_HPP_

#include <iostream>
#include <sstream>

/* consider adding boost thread id since we'll want to know whose writting and
 * won't want to repeat it for every single call */

/* consider adding policy class to allow users to redirect logging to specific
 * files via the command line
 */

enum loglevel_e
    {logERROR, logWARNING, logINFO, logDEBUG, logDEBUG1, logDEBUG2, logDEBUG3, logDEBUG4};

class logIt
{
public:
    logIt(loglevel_e _loglevel = logERROR) {
        _buffer << _loglevel << " :" 
            << std::string(
                _loglevel > logDEBUG 
                ? (_loglevel - logDEBUG) * 4 
                : 1
                , ' ');
    }

    template <typename T>
    logIt & operator<<(T const & value)
    {
        _buffer << value;
        return *this;
    }

    ~logIt()
    {
        _buffer << std::endl;
        // This is atomic according to the POSIX standard
        // http://www.gnu.org/s/libc/manual/html_node/Streams-and-Threads.html
        std::cerr << _buffer.str();
    }

private:
    std::ostringstream _buffer;
};

extern loglevel_e loglevel;

#define log(level) \
if (level > loglevel) ; \
else logIt(level)

#endif

Используйте это так:

// define and turn off for the rest of the test suite
loglevel_e loglevel = logERROR;

void logTest(void) {
    loglevel_e loglevel_save = loglevel;

    loglevel = logDEBUG4;

    log(logINFO) << "foo " << "bar " << "baz";

    int count = 3;
    log(logDEBUG) << "A loop with "    << count << " iterations";
    for (int i = 0; i != count; ++i)
    {
        log(logDEBUG1) << "the counter i = " << i;
        log(logDEBUG2) << "the counter i = " << i;
    }

    loglevel = loglevel_save;
}
3 голосов
/ 30 мая 2011

Если вы спрашиваете о каркасе ведения журналов и работаете в C ++, посмотрите Apache log4cxx . Чтобы понять архитектуру, требуется несколько минут, но как только вы это сделаете, вы поймете, что это хороший баланс гибкости, простоты использования и (как говорится) производительности.

log4cxx имеет очень гибкую конфигурацию, благодаря которой вы можете, без перекомпиляции, контролировать, куда выводится (файл / вращающийся файл / консоль / и т. Д.), Уровень отладки подкомпонентов (например, вы хотите сосредоточиться на определенный класс / компонент, поэтому вы устанавливаете его на уровень DEBUG, а остальные на INFO), формат записей журнала и т. д.

Если вы спрашиваете о общих рекомендациях о том, как ведется запись в журнал, я такого не видел (не то, что на самом деле искал). Я думаю, что это в основном эмпирически - вы решаете, какая информация необходима на каждом уровне ведения журнала, например, INFO, DEBUG и т. Д., И вы уточняете ее в соответствии с потребностями вашего клиента и вашего клиента (не забывайте, что ваш клиент также может быть клиентом журнал, в зависимости от вашего проекта).

2 голосов
/ 29 мая 2011

Зависит от того, что вы подразумеваете под «ведением журнала».Одна из форм - просто предоставить метод для печати содержимого некоторого объекта в выходной поток.Для объекта типа ClassName это влечет за собой написание оператора вставки для класса:

std::ostream &operator<< (std::ostream &stream, const ClassName & obj) {
   // Implementation elided
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...