【发布时间】:2011-02-16 22:41:41
【问题描述】:
我正在处理一个 J2EE Web 应用程序,当发生异常时,我想获取有关异常的一些基本详细信息并记录它。我正在记录的消息应该是非常基本的,对于运行 Web 服务器的人来说可能意味着什么。
使用e.getMessage() 是最好的记录方式吗?谢谢。
【问题讨论】:
标签: java logging jakarta-ee exception
我正在处理一个 J2EE Web 应用程序,当发生异常时,我想获取有关异常的一些基本详细信息并记录它。我正在记录的消息应该是非常基本的,对于运行 Web 服务器的人来说可能意味着什么。
使用e.getMessage() 是最好的记录方式吗?谢谢。
【问题讨论】:
标签: java logging jakarta-ee exception
我默认获取整个堆栈跟踪,这样我可以看到错误发生时发生的更多上下文。
如果您使用 log4j 并将异常传递到其日志记录方法之一,它将打印您提供的任何消息,以及异常的消息及其堆栈跟踪:
log.error("caught an exception", throwable);
如果您有容易出错的事情,例如对 Web 服务的调用,您可以将抛出的异常包装在一个异常中,并为其分配一个非常清晰的消息,这样当管理员看到它时,该消息就会告诉他们发生了什么。
就此而言,您可以保留单独的日志,一个带有用于开发人员的堆栈跟踪,另一个用于编写管理员友好的消息。您可以有一个异常处理程序,尝试将异常映射到友好消息,然后将该消息写入管理日志。
【讨论】:
可能。问题是至少没有调用方法信息,这不是很有帮助
考虑类似以下的事情
/**
* Returns <i>class.method:linenumber</i> of the caller (or, more accurately
* the caller of the caller).
* </p>
*
* <p>
* Returns unknown if stacktrace is mucked up. Uses reflection and string
* concatenation, so don't overuse this for trivial matters. For exception
* handling and for logging, on the other hand, it is useful.
*
* @return method name of caller's caller and line number (String)
*/
public static String returnCaller( Class ignoreMe )
{
String ignoreClass = ignoreMe.getName();
StackTraceElement[] steArr = new Throwable().getStackTrace();
if (steArr != null)
{
// subscript 1 is returnCaller().
// subscript 2 is the caller of returnCaller()
// subscript 3 is the caller of the caller of returnCaller()...
for( int i = 0; i < steArr.length; i++)
{
if (steArr[i] == null)
break;
String myclass = steArr[i].getClassName();
if (myclass.equals(ErrorHandle.class.getName()))
continue;
if (ignoreClass.equals(myclass))
continue;
return steArr[i].getClassName()
+ "."
+ steArr[i].getMethodName()
+ ":"
+ steArr[i].getLineNumber();
}
}
return "unknown";
}
【讨论】:
Integer.valueOf(String)。实际抛出异常的类对你没有多大好处。
只记录异常消息不是一个好主意;您丢失了异常发生在哪一行,这使得在代码中查找记录的异常大多数时候都是一场噩梦。
记录整个异常/堆栈跟踪。
【讨论】:
如果您只是想通知系统管理员,出现了问题,但没有开发人员需要查看它,因为这是一些暂时的已知问题,或者可以由系统管理员解决,一个好的描述性消息就足够了。在所有其他情况下,每个开发人员都会非常感谢获得完整的堆栈跟踪以及异常发生时的系统状态(如果可用)(输入参数等...)。
【讨论】:
我做过非常相似的事情。但首先,您根本不需要向用户传达错误是什么。告诉他们错误是如何发生的是没有意义的,因为无论如何您都会记录它。 (如果用户知道由于 NPE 或 IO 错误而发生错误是否有意义,即使您将其重命名为更“友好”的术语)?
首先您可能需要考虑re-throwing all of your Exceptions as runtime (unchecked) exceptions。这将强制集中和一致地记录错误。否则,您将不得不希望错误处理代码的每个实例都能正确记录它。重新抛出你的 SQLExceptions 例如:
try{
conn.close();
} catch(SQLException ex){
//logger.error("Cannot close connection"); //don't log this here, do it centrally
throw new RuntimeException(ex);
}
您将希望将用户转发到一般错误页面,只需告诉他们发生了错误。这向他们表明,他们所做的任何事情都没有得到处理。这非常重要,这样他们就不会反击并一遍又一遍地尝试输入付款。让他们知道出了点问题,然后 (a) 联系帮助台或 (b) 在默认错误页面中放置一个表格,该页面可以记录故障单或向帮助台发送电子邮件。为此,您需要在 web.xml 中定义它:
<error-page>
<error-code>500</error-code>
<location>/Error.jsp</location>
</error-page>
接下来,在 error.jsp 页面(或 servlet)中,如果您的容器允许您将堆栈跟踪引用为 request.getAttribute("javax.servlet.error.message"));,则在此处记录错误。
OR,创建一个仅作用于响应的过滤器,如下所示:
try {
chain.doFilter(req, res);
} catch (Exception e) {
logger.error("pass any Mapped Diagnostic Context here", e); //log here, centrally
throw new RuntimeException(e); //throws back to the container so that the error page will be seen
}
这将捕获所有传播的异常(未检查和未捕获),记录它们,然后重新抛出它们,以便它们调用错误页面。这样会报错
最后,您可能需要考虑使用 log4j 并使用一个附加程序,该附加程序将输出到您可以查看错误的地方,而无需等待运营团队将它们发送给您。如果您定期维护应用程序,这种方式会容易得多。
【讨论】: