如何从 Java 中的生产代码中删除调试语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32041/
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-10-29 10:48:10  来源:igfitidea点击:

How to remove debug statements from production code in Java

javadebuggingcompiler-construction

提问by Jonathan

Is it possible for the compiler to remove statements used for debugging purposes (such as logging) from production code? The debug statements would need to be marked somehow, maybe using annotations.

编译器是否可以从生产代码中删除用于调试目的(例如日志记录)的语句?调试语句需要以某种方式标记,可能使用注释。

It's easy to set a property (debug = true) and check it at each debug statement, but this can reduce performance. It would be nice if the compiler would simply make the debug statements vanish.

设置属性 (debug = true) 并在每个调试语句中检查它很容易,但这会降低性能。如果编译器只是让调试语句消失,那就太好了。

回答by Mark Renouf

Two recommendations.

两个建议。

First:for real logging, use a modern logging package like log4j or java's own built in logging. Don't worry about performance so much, the logging level check is on the order of nanoseconds. (it's an integer comparison).

首先:对于真正的日志记录,使用现代日志记录包,如 log4j 或 java 自己的内置日志记录。不要太担心性能,日志级别检查是纳秒级的。(这是一个整数比较)。

And if you have more than a single log statement, guard the whole block:

如果您有多个日志语句,请保护整个块:

(log4j, for example:)

(log4j,例如:)

if (logger.isDebugEnabled()) {

  // perform expensive operations
  // build string to log

  logger.debug("....");
}

This gives you the added ability control logging at runtime. Having to restart and run a debug build can be very inconvenient.

这为您提供了在运行时控制日志记录的附加能力。必须重新启动并运行调试版本可能非常不方便。

Second:

第二:

You may find assertionsare more what you need. An assertion is a statement which evaluates to a boolean result, with an optional message:

您可能会发现断言更符合您的需求。断言是评估为布尔结果的语句,带有可选消息:

 assert (sky.state != FALLING) : "The sky is falling!";

Whenever the assertion results in a false, the assertion fails and an AssertionError is thrown containing your message (this is an unchecked exception, intended to exit the application).

每当断言结果为 false 时,断言就会失败并抛出包含您的消息的 AssertionError(这是一个未经检查的异常,旨在退出应用程序)。

The neat thing is, these are treated special by the JVM and can toggled at runtime down to the class level, using a VM parameter (no recompile needed). If not enabled, there is zero overhead.

巧妙的是,这些被 JVM 特殊对待,并且可以在运行时切换到类级别,使用 VM 参数(不需要重新编译)。如果未启用,则开销为零。

回答by izb

public abstract class Config
{
    public static final boolean ENABLELOGGING = true;
}


import static Config.*;

public class MyClass
{
    public myMethod()
    {
        System.out.println("Hello, non-logging world");

        if (ENABLELOGGING)
        {
            log("Hello, logging world.");
        }
    }
}

The compiler will remove the code block with "Hello, logging world." in it if ENABLE_LOGGING is set to true because it's a static final value. If you use an obfuscator such as proguard, then the Config class will vanish too.

编译器将删除带有“Hello, logging world”的代码块。如果 ENABLE_LOGGING 设置为 true,则在其中,因为它是静态最终值。如果您使用混淆器(例如 proguard),那么 Config 类也会消失。

An obfuscator would also allow things like this instead:

混淆器也允许这样的事情:

public class MyClass
{
    public myMethod()
    {
        System.out.println("Hello, non-logging world");

        Log.log("Hello, logging world.");
    }
}


import static Config.*;

public abstract class Log
{
    public static void log(String s)
    {
        if (ENABLELOGGING)
        {
            log(s);
        }
    }
}

The method Log#log would reduce to nothing in the compiler, and be removed by the obfuscator, along with any calls to that method and eventually even the Log class would itself be removed.

方法 Log#log 将在编译器中减少到任何内容,并被混淆器删除,以及对该方法的任何调用,最终甚至 Log 类本身也将被删除。

回答by Dana the Sane

Another possibility is to put the if statement within your logging function, you get less code this way, but at the expense of some extra function calls.

另一种可能性是将 if 语句放在你的日志函数中,这样你得到的代码更少,但代价是一些额外的函数调用。

I'm also not a big fan of completely removing the debug code. Once you're in production, you'll probably need access to debug messages if something goes wrong. If you remove all of your code level debugging, than this isn't a possibility.

我也不喜欢完全删除调试代码。进入生产环境后,如果出现问题,您可能需要访问调试消息。如果您删除所有代码级调试,则这是不可能的。

回答by Hiep

This "trick" seems to make your debug statements vanished

这个“技巧”似乎让你的调试语句消失了

public static final boolean DEBUG = false;

if (DEBUG) { //disapeared on compilation }

The postsaid that javacis smart enough to check the static final booleanand exclude the debug statements. (I did not personally try it)

帖子说这javac足以检查static final boolean并排除调试语句。(我没有亲自尝试过)

For logging, I personally donot like to see code like:

对于日志记录,我个人不喜欢看到如下代码:

if (logger.isDebugEnabled()) {
    logger.debug("....");
}
realImportantWork();

The logging things distracts me from the realImportantWork(). The right way for me is:

日志记录使我从realImportantWork(). 对我来说正确的方法是:

logger.debug("....");
realImportantWork()

plus the config which excludes all debug messages on Production.

加上排除生产中所有调试消息的配置。

I mean that the logger.isDebugEnabled()control should be the job of the logging framework, not my job. Most logging framework support concepts like "logger", "LogLevel".. which can do the trick.

我的意思是logger.isDebugEnabled()控制应该是日志框架的工作,而不是我的工作。大多数日志框架都支持诸如“logger”、“LogLevel”之类的概念,它们可以解决问题。

回答by HadleyHope

I would also highly recommend using a logging framework.

我还强烈建议使用日志记录框架。

The logger.IsDebugEnabled()is not mandatory, it is just that it can be faster to check whether the system is in the debug level before logging.

logger.IsDebugEnabled()不是强制性的,只是在登录之前检查系统是否处于调试级别可以更快。

Using a logging framework means you can configure logging levels on the fly without restarting the application.

使用日志框架意味着您可以在不重新启动应用程序的情况下动态配置日志级别。

You could have logging like:

你可以有这样的日志记录:

logger.error("Something bad happened")
logger.debug("Something bad happend with loads more detail")

回答by Peter Stuifzand

Java contains some sort of preprocessor of its own. It's called APT. It processes and generates code. At the moment I'm not sure how this should work (I haven't tried it). But it seems to be used for these kind of things.

Java 包含某种自己的预处理器。它被称为APT。它处理并生成代码。目前我不确定这应该如何工作(我还没有尝试过)。但它似乎被用于这类事情。

回答by sparkes

Use Java Preprocessor? (google foo low but this is a link to the old Joel forums discussing it)

使用Java 预处理器?(谷歌 foo 低,但这是一个链接到旧的 Joel 论坛讨论它)

回答by cschol

To directly answer your question: I don't know.

直接回答你的问题:我不知道。

But here is another solution to your problem: In my mind, there are two statements that collide with each other here: "debug statements" and "production code".

但这是您问题的另一种解决方案:在我看来,这里有两个相互冲突的语句:“调试语句”和“生产代码”。

What is the purpose of debug statements? Help to get rid of bugs while (unit) testing. If a piece of software is properly tested and works according to the requirements, debug statements are nothing else but OBSOLETE.

调试语句的目的是什么?帮助在(单元)测试时摆脱错误。如果一个软件经过适当的测试并按照要求工作,那么调试语句就是过时的。

I strongly disagree with leaving any debug statements in production code. I bet nobody bothers testing side-effects of debug code in production code. The code probably does what it's supposed to do, but does it do more than that? Do all your #defines work correctly and really take ALL of the debug code out? Who analyzes 100000 lines of pre-processed code to see if all the debug stuff is gone?

我强烈反对在生产代码中留下任何调试语句。我打赌没有人会在生产代码中测试调试代码的副作用。代码可能做了它应该做的事情,但它做的还不止这些吗?你所有的#defines 是否都能正常工作并且真的把所有的调试代码都去掉了?谁分析 100000 行预处理代码以查看是否所有调试内容都消失了?

Unless we have a different definition of production code, you should consider taking out the debug statements after the code is tested and be done with it.

除非我们对生产代码有不同的定义,否则您应该考虑在代码测试完成后取出调试语句。