objective-c 真的不应该在生产代码上使用 NSLog() 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/300673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 20:54:44  来源:igfitidea点击:

Is it true that one should not use NSLog() on production code?

iphoneobjective-cnslog

提问by jpm

I was told this a few times in this very site, but I wanted to make sure this is really the case.

我在这个网站上被告知过几次,但我想确保情况确实如此。

I was expecting to be able to sprinkle NSLog function calls throughout my code, and that Xcode/gcc would automatically strip those calls out when building my Release/Distribution builds.

我希望能够在我的代码中散布 NSLog 函数调用,并且在构建我的发布/分发版本时,Xcode/gcc 会自动删除这些调用。

Should I avoid using this? If so, what alternatives are most common between experienced Objective-C programmers?

我应该避免使用它吗?如果是这样,经验丰富的 Objective-C 程序员之间最常见的替代方法是什么?

回答by Marc Charbonneau

Preprocessor macros are indeed great for debugging. There's nothing wrong with NSLog(), but it's simple to define your own logging function with better functionality. Here's the one I use, it includes the file name and line number to make it easier to track down log statements.

预处理器宏确实非常适合调试。NSLog() 没有任何问题,但是使用更好的功能定义自己的日志记录函数很简单。这是我使用的一个,它包括文件名和行号,以便更容易地跟踪日志语句。

#define DEBUG_MODE

#ifdef DEBUG_MODE
    #define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
    #define DebugLog( s, ... ) 
#endif

I found it easier to put this entire statement in the prefix header rather than its own file. You could, if you wanted, build a more complicated logging system by having DebugLog interact with normal Objective-C objects. For instance, you could have a logging class that writes to its own log file (or database), and includes a 'priority' argument you could set at runtime, so debug messages are not shown in your release version, but error messages are (if you did this you could make DebugLog(), WarningLog(), and so on).

我发现将整个语句放在前缀头而不是它自己的文件中更容易。如果您愿意,您可以通过让 DebugLog 与普通的 Objective-C 对象交互来构建更复杂的日志记录系统。例如,您可以有一个日志记录类写入其自己的日志文件(或数据库),并包含您可以在运行时设置的“优先级”参数,因此您的发布版本中不会显示调试消息,但错误消息是(如果你这样做,你可以使 DebugLog()、WarningLog() 等等)。

Oh, and keep in mind #define DEBUG_MODEcan be re-used in different places in your application. For example, in my application I use it to disable license key checks and only allow the application to run if it's before a certain date. This lets me distribute a time limited, fully functional beta copy with minimal effort on my part.

哦,请记住#define DEBUG_MODE可以在您的应用程序的不同地方重复使用。例如,在我的应用程序中,我使用它来禁用许可证密钥检查,并且只允许应用程序在某个日期之前运行。这让我可以以最少的努力分发时间有限、功能齐全的测试版副本。

回答by roel

Put this 3 lines at the end of -prefix.pch file:

将这 3 行放在 -prefix.pch 文件的末尾:

#ifndef DEBUG
  #define NSLog(...) /* suppress NSLog when in release mode */
#endif

You don't need to define anything into your project, because DEBUGis defined in your build setting by default when you create your project.

你不需要在你的项目中定义任何东西,因为DEBUG在你创建你的项目时默认在你的构建设置中定义。

回答by Matthew Schinckel

NSLog calls can be left in production code, but should only be there for truly exceptional cases, or information that it is desired that will be logged to the system log.

NSLog 调用可以留在生产代码中,但应该只在真正的例外情况下,或者需要记录到系统日志中的信息时才会出现。

Applications which litter the system log are annoying, and come across as unprofessional.

乱丢系统日志的应用程序很烦人,而且看起来很不专业。

回答by ohhorob

I can't comment on Marc Charbonneau's answer, so I'll post this as an answer.

我无法对Marc Charbonneau 的回答发表评论,因此我将其发布为答案。

Further to adding the macro to your pre-compiled header, you can use the Target build configurations to control the defining (or lack of defining) the DEBUG_MODE.

进一步将宏添加到您的预编译头文件中,您可以使用目标构建配置来控制定义(或缺少定义)DEBUG_MODE.

If you select "Debug" active configuration, DEBUG_MODEwill be defined, and the macro expands to the full NSLogdefinition.

如果选择“调试”活动配置,DEBUG_MODE将被定义,并且宏扩展为完整NSLog定义。

Selecting the "Release" active configuration will not define DEBUG_MODEand your NSLogging is omitted from the release build.

选择“发布”活动配置将不会定义,DEBUG_MODE并且NSLog发布版本中会省略您的ging。

Steps:

脚步:

  • Target > Get Info
  • Build tab
  • Search for "PreProcessor Macros" (or GCC_PREPROCESSOR_DEFINITIONS)
  • Select Configuration: Debug
  • Edit Definition at this Level
  • Add DEBUG_MODE=1
  • Select Configuration: Release
  • confirm DEBUG_MODEis not set in GCC_PREPROCESSOR_DEFINITIONS
  • 目标 > 获取信息
  • 构建选项卡
  • 搜索“预处理器宏”(或GCC_PREPROCESSOR_DEFINITIONS
  • 选择配置:调试
  • 在此级别编辑定义
  • 添加 DEBUG_MODE=1
  • 选择配置:发布
  • 确认DEBUG_MODE未设置GCC_PREPROCESSOR_DEFINITIONS

if you omit the '=' character in the definition, you will get an error from the preprocessor

如果您在定义中省略了 '=' 字符,您将收到来自预处理器的错误

Also, paste this comment (shown below) above the macro definition to remind you where the DEBUG_MACROdefine comes from ;)

另外,将此注释(如下所示)粘贴在宏定义上方以提醒您DEBUG_MACRO定义的来源;)

// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
//               = Debug:   DEBUG_MODE=1

回答by e.James

EDIT:The methodposted by Marc Charbonneau, and brought to my attention by sho, is far better than this one.

编辑:方法通过贴马克·博诺,并提醒我注意,远远比这更好的一个。

I have deleted the portion of my answer which suggested using an empty function to disable logging when debug mode is disabled. The portion that deals with setting an automatic preprocessor macro is still relevant, so it remains. I have also edited the name of the preprocessor macro so that it fits better with Marc Charbonneau's answer.

我已经删除了我的答案中建议在禁用调试模式时使用空函数禁用日志记录的部分。处理设置自动预处理器宏的部分仍然是相关的,所以它仍然存在。我还编辑了预处理器宏的名称,使其更符合 Marc Charbonneau 的回答。



To achieve the automatic (and expected) behaviour in Xcode:

要在 Xcode 中实现自动(和预期)行为:

In the project settings, go to the "Build" tab, and select the "Debug" configuration. Find the "Preprocessor Macros" section, and add a macro named DEBUG_MODE.

在项目设置中,转到“Build”选项卡,然后选择“Debug”配置。找到“预处理器宏”部分,并添加一个名为DEBUG_MODE.

...

...

EDIT:See Marc Charbonneau's answerfor the proper way to enable and disable logging with the DEBUG_MODEmacro.

编辑:有关使用宏启用和禁用日志记录的正确方法,请参阅Marc Charbonneau 的回答DEBUG_MODE

回答by August

I agree with Matthew. There's nothing wrong with NSLog in production code. In fact, it can be useful to the user. That said, if the only reason you're using NSLog is to help debug, then, yes, that should be removed before you release.

我同意马修的意见。生产代码中的 NSLog 没有任何问题。事实上,它可能对用户有用。也就是说,如果您使用 NSLog 的唯一原因是帮助调试,那么,是的,应该在您发布之前将其删除。

Furthermore, since you've tagged this as an iPhone question, NSLog takes resources, which is something the iPhone has precious little of. If you're NSLogging anythingon the iPhone, that takes away processor time from your app. Use it wisely.

此外,由于您已将此标记为 iPhone 问题,因此 NSLog 会占用资源,而 iPhone 却很少使用这些资源。如果你在iPhone 上NSLogging任何东西,那会从你的应用程序中占用处理器时间。明智地使用它。

回答by Andrew

The simple truth is that NSLog is just plain slow.

简单的事实是 NSLog 只是很慢。

But why? To answer that question, let's find out what NSLog does, and then how it does it.

但为什么?为了回答这个问题,让我们看看 NSLog 做了什么,然后它是如何做的。

What does NSLog do exactly?

NSLog 究竟做了什么?

NSLog does 2 things:

NSLog 做了两件事:

It writes log messages to the Apple System Logging (asl) facility. This allows log messages to show up in Console.app. It also checks to see if the application's stderr stream is going to a terminal (such as when the application is being run via Xcode). If so it writes the log message to stderr (so that it shows up in the Xcode console).

它将日志消息写入 Apple System Logging (asl) 工具。这允许日志消息显示在 Console.app 中。它还检查应用程序的 stderr 流是否会进入终端(例如当应用程序通过 Xcode 运行时)。如果是这样,它将日志消息写入 stderr(以便它显示在 Xcode 控制台中)。

Writing to STDERR doesn't sound difficult. That can be accomplished with fprintf and the stderr file descriptor reference. But what about asl?

写入 STDERR 听起来并不困难。这可以通过 fprintf 和 stderr 文件描述符参考来完成。但是asl呢?

The best documentation I've found about ASL is a 10 part blog post from Peter Hosey: link

我发现的有关 ASL 的最佳文档是 Peter Hosey 的 10 部分博客文章:链接

Without going into too much detail, the highlight (as it concerns performance) is this:

在不涉及太多细节的情况下,亮点(因为它涉及性能)是这样的:

To send a log message to the ASL facility, you basically open a client connection to the ASL daemon and send the message. BUT - each thread must use a separate client connection. So, to be thread safe, every time NSLog is called it opens a new asl client connection, sends the message, and then closes the connection.

要将日志消息发送到 ASL 工具,您基本上要打开到 ASL 守护程序的客户端连接并发送消息。但是 - 每个线程必须使用单独的客户端连接。因此,为了线程安全,每次调用 NSLog 时,它都会打开一个新的 asl 客户端连接,发送消息,然后关闭连接。

Resources could be found here& here.

可以在此处此处找到资源。

回答by jww

From a security point of view, it depends on what is being logged. If NSLog(or other loggers) is writing sensitive information, then you should remove the logger in production code.

从安全的角度来看,这取决于记录的内容。如果NSLog(或其他记录器)正在写入敏感信息,那么您应该在生产代码中删除记录器。

From an auditing point of view, the auditor does not want to look at each use of NSLogto ensure its not logging sensitive information. He/she will simply tell you to remove the logger.

从审计的角度来看,审计员不希望查看每个使用NSLog以确保其不记录敏感信息。他/她只会告诉您删除记录器。

I work with both groups. We audit code, write the coding guides, etc. Our guide requires that logging is disabled in production code. So the internal teams know not to try it ;)

我和这两个团体一起工作。我们审核代码,编写编码指南等。我们的指南要求在生产代码中禁用日志记录。所以内部团队知道不要尝试;)

We will also reject an external app that logs in production because we don't want to accept the risk associated with accidentally leaking sensitive information. We don't care what the developer tells us. Its simply not worth our time to investigate.

我们还将拒绝登录生产的外部应用程序,因为我们不想接受与意外泄露敏感信息相关的风险。我们不在乎开发者告诉我们什么。它根本不值得我们花时间去调查。

And remember, we define 'sensitive', and not the developer ;)

请记住,我们定义的是“敏感”,而不是开发人员;)

I also perceive an app which performs lots of logging as an app ready to implode. There's a reason so much logging is performed/needed, and its usually not stability. Its right up there with 'watchdog' threads that restart hung services.

我还认为一个执行大量日志记录的应用程序是一个准备内爆的应用程序。执行/需要执行如此多的日志记录是有原因的,并且通常不稳定。它就在那里,带有重新启动挂起服务的“看门狗”线程。

If you have never been through a Security Architecture (SecArch) review, these are the sorts of things we look at.

如果您从未经历过安全架构 (SecArch) ,那么我们会关注这些内容。

回答by user151019

As noted in other answers you can use a #define to alter whether NSLog is used or not at compile time.

正如其他答案中所述,您可以使用 #define 来更改在编译时是否使用 NSLog。

However a more flexible way is to use a logging library like Cocoa LumberHymanthatallows you to change whether something is logged at runtime as well.

然而,更灵活的方法是使用像Cocoa LumberHyman这样的日志库,它允许您更改是否也在运行时记录某些内容。

In your code replace NSLog by DDLogVerbose or DDLogError etc, add a #import for the macro definitions etc and setup the loggers, often in the applicationDidFinishLaunching method.

在您的代码中,用 DDLogVerbose 或 DDLogError 等替换 NSLog,为宏定义等添加 #import 并设置记录器,通常在 applicationDidFinishLaunching 方法中。

To have the same effect as NSLog the configuration code is

为了和 NSLog 有同样的效果,配置代码是

[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];

回答by MaddTheSane

You shouldn't be needlessly verbose with printf or NSLog in release code. Try only doing a printf or NSLog if the app has something bad happen to it, I.E. an unrecoverable error.

您不应该在发布代码中使用 printf 或 NSLog 进行不必要的冗长。如果应用程序发生了不好的事情,即无法恢复的错误,请仅尝试执行 printf 或 NSLog。