在Java中选择性打印堆栈跟踪

9

我正在创建一个Java应用程序,可能会抛出异常。我在try-catch块中处理这些异常,并打印适当的消息,以便业务用户在失败时不必看到丑陋的堆栈跟踪。

但是现在当我调试时,我希望以这样的方式调用JAR文件,它将为我打印堆栈跟踪,以便我可以知道问题所在。

有人能告诉我如何实现这个目标吗?


你在使用日志记录器吗?还是只是使用 System.out.println 语句输出信息? - RonK
4个回答

19
您可以使用slf4j作为门面,以便能够快速更改实现,并使用logback作为日志记录的实现。 slf4j和logback的组合目前是一个非常高效的日志记录系统。如果您想要使用另一个实现,如log4j、JDK 1.4或Jacarta Commons Logging,则只需将实现(绑定)的jar更改为所需的jar即可。以下是如何使用slf4j与logback的快速用户手册。

设置您的环境

首先,您应该导入使用slf4j所需的必要jar文件。

Eclipse指南

  • 在Eclipse中找到您的项目,右键单击它。选择属性

  • 从左面板中选择Java Build Path

  • 选择选项卡

  • 单击添加外部JAR

  • 找到您的提取文件夹并添加logback-core-1.0.7.jarlogback-classic-1.0.7.jar和来自slf4j-1.7.0 文件夹的slf4j-api-1.7.0.jar。单击确定返回项目。

Netbeans指南

  • 在Netbeans中找到您的项目,右键单击它。选择属性

  • 从左面板中选择

  • 选择编译选项卡

  • 单击添加JAR /文件夹

  • 找到你提取的文件夹,从logback-1.0.7文件夹中添加logback-core-1.0.7.jar、logback-classic-1.0.7.jar以及从slf4j-1.7.0文件夹中添加slf4j-api-1.7.0.jar。单击“确定”返回项目。

*如果您没有使用上述任何环境,则应手动将以上3个JAR文件添加到您的类路径中。根据您的操作系统,有不同的程序要遵循。


使用日志框架

首先,您应该导入所需的依赖项:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

每个需要记录日志的类都应该有一个私有的日志记录器:

private final Logger logger = (Logger) LoggerFactory.getLogger(this.getClass())

为每个类单独设置日志记录器可以提供更大的灵活性和更容易改变日志级别(WARN,ERROR,INFO,DEBUG)。

根据您想要使用的日志级别,您应该有

logger.info("Your info message");

logger.error("Your error message");

logger.debug("Your debug message");

logger.warn("Your warn message");

还有一种可能性是根据您的需求使用更复杂的方法调用。例如,如果您想要调试并显示堆栈跟踪,您应该使用

也可以使用更复杂的方法调用,具体取决于您的需求。例如,如果您想要进行调试并显示堆栈跟踪,您应该使用


logger.debug("Your debug message",e);
(e stands for a catched exception).
例如:
try{       
   //some code  
}catch (IOException e){
   logger.debug("An IOException was thrown at this method ",e);       
   logger.error("An IOException was thrown at this method ",e); 
}
*当前情况下,不需要添加任何其他配置即可拥有一个简单的日志记录系统。如果您想要更高级的配置,请阅读我下面发布的logback高级设置。

logback的高级设置

为了拥有更高级的日志记录系统,您应该创建一个额外的文件,其中包含所有的日志记录配置。对于这个例子,我将使用logback.xml。有关logback不同文件的更多信息,请参阅logback配置

此时,您应该创建一个名为“资源”的文件夹,并将其添加到项目的构建路径中。

Eclipse 指南

  • 创建一个名为“资源”的文件夹(您必须在项目中看到该文件夹)。

  • 在Eclipse中找到您的项目,右键单击它。选择属性

  • 从左侧面板中选择Java Build Path

  • 选择Source选项卡

  • 单击添加文件夹

  • 选中您已创建的resources文件夹并单击“确定”。再次单击“确定”返回到项目。

  • 此时,您应该将资源文件夹视为一个包。

Netbeans 指南

  • 创建一个名为“资源”的文件夹(它在项目视图中不可见,只在文件视图中可见)

  • 在Netbeans中找到您的项目,右键单击它。选择属性

  • 从左侧面板中选择Sources

  • 在源程序包文件夹中单击添加文件夹

  • 选择资源文件夹并单击“确定”。

  • 您应该看到已创建的文件夹作为一个包。

*文件夹的名称可以是任何您喜欢的名称。为方便起见,我将其命名为resources。

以下适用于Eclipse和Netbeans。

*如果您的类路径中没有以下文件来指定日志框架的特定设置,则根记录器级别会自动分配为DEBUG。这意味着所有的日志级别都会被记录下来。Debug是更高级别的。

  • 创建一个名为logback.xml的文件夹,并将其放置在resources文件夹中。
  • 在logback.xml中放置以下标记:

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>   
        <encoder>
            <pattern>[%-5level] - %msg%n
            </pattern>
        </encoder>
    </appender>
    
    
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <append>false</append>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %class - %msg%n
            </pattern>
        </encoder>
        <File>log/log.txt</File>
    </appender>
    
    
    <logger name="org.test" level="INFO" additivity="false">
        <appender-ref ref="STDOUT" />
    </logger>
    
    <logger name="org.test" level="DEBUG" additivity="false">
        <appender-ref ref="FILE" />
    </logger>
    
    <root level="OFF">
    
    </root>
    

    上述配置包含2个不同的appender,一个在控制台,一个在名为log.txt的文件中。该文件将被放置在名为log的文件夹中。如果文件夹log不存在,则会自动创建。

    你要使用的模式取决于你和你的消息有多少信息量。在当前配置中,控制台appender比文件appender更少描述性,仅显示日志级别和消息,而文件appender包含日志级别、线程名称、类名称、时间和消息。设置append值为false,以便在每次运行应用程序后创建新的日志文件。

    上述配置对同一包使用了2个不同的loggers。第一个logger仅在控制台打印info消息,而第二个logger将debug消息打印到文件中。这是通过使用放置在appender内部的filter来实现的。

    *在logger名称中,您可以使用您的类的完全限定名称或包名称。在此示例中,我假设包结构org.test并将类放置在此包中。如果您有类的完全限定名称,则日志记录配置仅适用于此类。如果您使用包名称,则该包中的所有类都将遵循上述配置。

    有许多不同的方法可以使用appender和loggers,这取决于您的需求和程序的复杂性。根据您描述的情况,我相信上述解决方案可以满足您的需求。

    P.S. 要获得更详细的定义和更高级的配置,请参阅Logback手册


14

为什么不使用日志级别?

DEBUG 用于技术错误, 而使用 INFOERROR 记录业务代码,这样用户更容易理解。


1
返回翻译的文本: log.warn("我的错误消息"); log.info("更多 "+technical+" 细节 "+e.getMessage()); log.debug(exception); - Peter Lawrey
这不完全是我要找的,但非常接近。感谢您的答复 :) - aa8y

1
通常使用记录器和不同的日志级别来处理这些事情。
您通常有3个日志级别,一般日志、警告和错误。 当您输出时,您决定消息属于哪个级别
当您启动应用程序时,您告诉记录器应该显示哪个级别。 对于您的用户,这将是ERROR,只有最糟糕的事情应该可见,对于自己,您会输出所有内容。

-3
创建两个具有相同包/名称的类,位于两个不同的位置。
public class PrintStackTraceUtil
 {
 public static void printStackTrace(Throwable err)
     {
     //ignore
     }
 }

并且

public class PrintStackTraceUtil
 {
 public static void printStackTrace(Throwable err)
     {
     err.printStackTrace();
     }
 }

在编译Java程序时,在源路径中只放置其中一个路径。


3
不良实践。你实际上建议分成两个不同的项目,一个带有日志记录,一个没有。你应该使用日志记录级别。 - Chobicus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接