Избегайте путаницы с отладочной информацией в коде - PullRequest
6 голосов
/ 20 июля 2011

Когда я пишу что-то, половина усилий тратится на добавление ясного и краткого вывода отладочной информации или функциональности , которую можно включить / отключить, когда что-то требует отладки.

Примером функциональности отладки является класс загрузчика, где я могу включить #define, который заставляет его «притворяться» загружающим файл и просто вернуть мне тот, который у меня уже есть.Таким образом, я могу проверить, что происходит, когда пользователь загружает файл, без необходимости ждать, пока сеть физически захватит файл каждый раз.Это хорошая функциональность, но код становится беспорядочным с # ifdefs.

В итоге я получаю набор из #define s, таких как

// #define DEBUG_FOOMODULE_FOO
// #define DEBUG_BARMODULE_THINGAMAJIG
// ...

, которые не комментируются длявещи, которые я хочу посмотреть.Код сам по себе выглядит примерно так:

- (void)something
{
    #ifdef DEBUG_FOOMODULE_FOO
    DebugLog(@"something [x = %@]", x);
    #endif
    // ...
    #ifdef DEBUG_FOOMODULE_MOO
    // etc
}

. Это прекрасно работает для написания / поддержки кода, но никак не влияет на его внешний вид.

Как люди в любом случае пишут долгосрочные «легкие» отладочные «вещи» на лету?

Примечание: Я говорю не только о NSLogging здесь ..Я также говорю о таких вещах, как загрузка, приведенная выше.

Ответы [ 3 ]

2 голосов
/ 20 июля 2011

Я прочитал несколько библиотек, прежде чем написать свою собственную, и увидел два подхода: макро + функции C ( NSLogger ) или макрос + Singleton ( GTMLogger , Cocoa Lumberjack ).

Я написал свою наивную реализацию здесь , используя macro + singleton. Я делаю это во время выполнения:

[Logger singleton].logThreshold = kDebug;
trace(@"hi %@",@"world); // won't show
debug(@"hi %@",@"world);

Вы можете сделать то же самое для пакетов вместо уровней журналов. Если я хочу, чтобы это ушло, я изменяю #defines. Вот этот код:

#define trace(args...) [[Logger singleton] debugWithLevel:kTrace line:__LINE__ funcName:__PRETTY_FUNCTION__ message:args];

if (level>=logThreshold){
  // ...
} 

Если вы хотите что-то более сложное, заглянуть в Lumberjack, у него есть функция класса регистра, чтобы переключать ведение журнала для некоторых классов.

1 голос
/ 29 июля 2011

Имея две функции и затем выбирая их соответствующим образом во время выполнения или при компиляции, мне кажется чистым подходом.Это позволяет иметь один download.c и один download_debug.c файл с одинаковыми функциями, за исключением разных реализаций.Затем свяжитесь с соответствующим, если вы строите с -DDEBUG или нет.

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

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

0 голосов
/ 20 июля 2011

В вашем случае у вас могут быть отдельные макросы журналирования, скажем MooLog и FooLog, которые все условно компилируются на основе отдельных флагов.

#ifdef DEBUG_FOO
#   define FooLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define FooLog(...)
#endif

#ifdef DEBUG_MOO
#   define MooLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define MooLog(...)
#endif

Ваша сложная логика теперь везде становится такой:

- (void)something
{
    // This only gets logged if the "DEBUG_FOO" flag is set.
    FooLog(@"something [x = %@]", x);
    // This only gets logged if the "DEBUG_MOO" flag is set.
    MooLog(@"Something else [y = %@]", y);
}
...