Я делаю небольшой проект, в общей сложности около 3-4 человек. Я хочу иметь надежный способ отладки приложения, например, журналами. Есть ли хорошие ресурсы о том, как его структурировать и тому подобное? Я много слышал от менеджеров проектов, что хорошая функция ведения журнала имеет решающее значение для каждого проекта, но я не уверен, как это сделать.
Как реализовать хорошую функцию отладки/ведения журнала в проекте
Ответ 1
Я нашел эту статью доктора Добба, Вход на С++, очень полезный в отношении этой темы.
Также на Dr. Dobb's: Высоко настраиваемая структура ведения журнала на С++
Если все, что вам нужно, это мертвый простой класс безопасного потока, который всегда выводится на 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;
}
Ответ 2
Если вы спрашиваете о фреймворках ведения журнала и работаете на С++, проверьте Apache log4cxx. Для понимания архитектуры требуется несколько минут, но как только вы это сделали, вы понимаете, что это хороший баланс гибкости, простоты использования и (как говорят) производительности.
log4cxx
имеет очень гибкую конфигурацию, благодаря которой вы можете управлять без перекомпиляции, где идет выход (файл/вращающийся файл/консоль/и т.д.), уровень отладки подкомпонентов (например, вы хотите сосредоточиться на конкретный класс/компонент, поэтому вы устанавливаете его на уровень DEBUG
, а остальная часть находится на INFO
), формат записей журнала и т.д.
Если вы спрашиваете о общих рекомендациях о том, как вести журнал, я не видел таких (не то, что я действительно искал). Я думаю, что это в основном эмпирическое - вы решаете, какая информация необходима для каждого уровня ведения журнала, такого как INFO, DEBUG и т.д., И вы уточняете его в соответствии с вашими и вашими потребностями (не забывайте, что ваш клиент также может быть клиентом log, в зависимости от вашего проекта).
Ответ 3
Зависит от того, что вы подразумеваете под "протоколированием". Одна из форм - просто предоставить способ печати содержимого какого-либо объекта в выходной поток. Для объекта типа ClassName это влечет за собой запись оператора вставки для класса:
std::ostream &operator<< (std::ostream &stream, const ClassName & obj) {
// Implementation elided
}
С этой целью вы можете распечатать объект типа ClassName в выходной поток. Это может быть весьма полезным, настолько полезным, что некоторым организациям требуется, чтобы каждый класс реализовал такой метод.