避免代码中调试内容混乱

发布于 2024-11-25 09:06:25 字数 707 浏览 3 评论 0 原文

当我编写某些内容时,一半的精力往往会花在添加清晰简洁的调试输出,或者在需要调试时可以启用/禁用的功能

调试功能的一个示例是一个下载器类,我可以在其中打开#define,使其“假装”下载文件,然后简单地将已有的文件交还给我。这样我就可以测试用户下载文件时会发生什么,而不必每次都等待网络物理抓取文件。这是一个很棒的功能,但是使用 #ifdefs 会使代码变得更加混乱。

我最终得到了一堆像这样的#define,

// #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...我还谈论上面的假装下载之类的东西。

When I write something, half the effort tends to go into adding clear and concise debug output, or functionality that can be enabled/disabled when that something needs debugging.

An example of debug functionality is a downloader class where I can turn on a #define which makes it "pretend" to download the file and simply hand me back the one I have already. That way I can test to see what happens when a user downloads a file, without having to wait for the network to physically grab the file every single time. This is great functionality to have, but the code gets messier with the #ifdefs.

I eventually end up with a bunch of #defines like

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

which are uncommented for the stuff I want to look at. The code itself turns out something like

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

This works great for writing / maintaining the code, but it does nothing for the appearance of the code.

How do people write effortless on-the-fly long-term debug "stuff" anyway?

Note: I'm not only talking about NSLogging here... I'm also talking about stuff like the pretend-download above.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

dawn曙光 2024-12-02 09:06:25

在编写自己的库之前,我阅读了几个库,并看到了两种方法:宏 + C 函数 (NSLogger) 或宏 + Singleton (GTMLoggerCocoa Lumberjack)。

我编写了我的幼稚实现 这里使用宏+单例。我在运行时执行此操作:

[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 进行更复杂的了解,它有一个注册类工具来切换某些类的日志记录。

I read several libraries before writing my own and saw two approaches: macro + C functions (NSLogger) or macro + Singleton (GTMLogger, Cocoa Lumberjack).

I wrote my naive implementation here using macro + singleton. I do this during runtime:

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

You could do the same for packages instead log levels. If I want it gone, I change the #defines. Here is the code involved:

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

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

If you want something more sophisticated look into Lumberjack, it has a register class facility to toggle logging for some classes.

内心激荡 2024-12-02 09:06:25

拥有两个函数,然后在运行时或编译时适当地选择它们对我来说似乎是一种干净的方法。这样就可以拥有一个 download.c 和一个 download_debug.c 文件,其功能相同,但实现不同。如果您是否使用 -DDEBUG 进行构建,则链接到适当的链接。

否则,使用函数指针对于运行时选择函数也同样有效。

如果您坚持将调试代码散布在您的函数中,那么您几乎会把自己设置为一团糟:)但是,您当然可以将这些片段分解为单独的函数,然后执行上述操作(或者使它们成为无操作,如在 DLog 示例中)。

Having two functions and then select them appropriately either at run-time or when compiling seems like a clean approach to me. This makes it possible to have one download.c and one download_debug.c file with the same functions except with different implementations. Then link with the appropriate one if you are building with -DDEBUG or not.

Otherwise, using function pointers works as well for run-time selecting functions.

If you insist of having debug code interspersed throughout your functions, you are pretty much setting up yourself for a mess :) But, you can of course break out those snippets into separate functions and then do the above (or make them no-ops as in the DLog example).

思念满溢 2024-12-02 09:06:25

对于您的情况,您可以有单独的日志记录宏,例如 MooLogFooLog,它们都根据单独的标志进行条件编译。

#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);
}

For your case, you could have separate logging macros, say MooLog and FooLog, that all conditionally compile based upon separate flags.

#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

Your complex logic everywhere now becomes this:

- (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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文