java - 如何在Exception的stackTrace中找到自己编码的类或过程

标签 java exception

我正在编写一个错误日志函数。
因此我需要记录一些信息,例如操作符、操作时间、错误消息和 api_name,其中的类或过程会引发异常。
我的问题是我不知道如何在java中获取api_name。
异常的部分堆栈跟踪是(我隐藏了我公司的名称):

com.xxxx.commons.database.DbException: {dbFlag: 101, dbMessage: ORA-01461}
    at com.xxxx.commons.database.DbHelper.throwDbException(DbHelper.java:933)
    at com.xxxx.commons.database.DbHelper.throwDbException(DbHelper.java:911)
    at com.xxxx.commons.database.DbHelper.runProcScalar(DbHelper.java:363)
    at com.xxxx.commons.database.DbHelper.runProcScalar(DbHelper.java:266)
    at com.xxxx.commons.database.DbHelper.runProcScalar(DbHelper.java:253)
    at com.xxxx.xxxxxx.xxxxxx.xxxx.xxxxxxx.saveErrorLog(xxxxxxxx.java:96)
    at com.xxxx.xxxxx.xxxx.xxxx.xxxx.save(xxxxxxxx.java:457)//I need this line
    at com.xxxx.xxx.xxxxxxxx.xxxxxxxx.finishActivity(xxxxxx.java:410)
    at com.xxxx.xxxx.xxxx.command.FinishActivityCommand.execute(xxxxxxxx.java:70)
    at com.xxxx.xxx.xxxxxx.xxxxxxxx.forward(xxxxxxx.java:79)
    at com.xxxx.xxx.xxxxxxx.xxxxx.execute(FlowCtrlAction.java:50)
    at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
    at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
    at com.xxxx.xxx.xxxxxx.xxxxxxxx.process(xxxxxxx.java:33)
    at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)

我需要第八行的className,而我的日志函数是第七行。 java代码是:

try{
    boolean r = store.xxxxxxx(caseId, runnerId, flowRecord);
    if (r) {
        return .........
    }
}catch(DbException e){
    saveLogDao.saveErrorLog(showType, businessUserId, caseId, stepCode, getExceptionStack(e), e.getMessage(), runnerId);
}

函数“getExceptionStack(e)”正在获取异常类的名称。
如何编码?非常感谢。

最佳答案

抛出异常的过程是堆栈中的第一个异常。但是,如果我答对了你的问题,你想跳过不相关的方法并将一些有意义的方法记录到错误日志中。

但是,这可能不是那么微不足道。如果您有一个方法“getUserCredentials()”,它调用“getUserName()”,它调用“getDatabaseConnection()”,它调用“connect()”,它会抛出异常 - 当您调用“getUserCredentials()”?当您在“generateReport()”中调用“getUserCredentials()”(在“main()”中调用)时,应记录哪个方法?

但是,有一些选项,例如分析注释,特别是如果您的代码已经使用了一些注释。

下面是一个示例,我在其中注释了当异常发生在其中更深处时应该出现在日志中的方法:

package stackoverflow;

import java.io.ObjectInputStream.GetField;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.Arrays;

public class StackTrace {

    @Retention(RetentionPolicy.RUNTIME)
    public static @interface TopLevelCallElement {

    }


    private void connect(){
        throw new RuntimeException("some database error");
    }

    private void getDatabaseConnection(){
        connect();
    }

    @TopLevelCallElement
    private void getName(){
        getDatabaseConnection();
    }

    @TopLevelCallElement
    public void getCredentials(){
        getName();
    }


    public static StackTraceElement getTopLevelFunction(Throwable exception){

        // iterate stack trace in reverse order
        StackTraceElement [] stackTrace = exception.getStackTrace();
        for (int i=stackTrace.length-1;i>=0;i--){
            StackTraceElement traceElement=stackTrace[i];
            try {
                Class<?> callerClass = Class.forName(traceElement.getClassName());

                for (Method method:callerClass.getDeclaredMethods()){
                    if (method.getName().equals(traceElement.getMethodName())){
                        // we got a method in a class that might be (unless it's an overloaded method)
                        // a method that really threw exception.
                        if (method.getAnnotation(TopLevelCallElement.class)!=null){
                            return traceElement;
                        }

                    }
                }

            } catch (ClassNotFoundException e) {
                // should not happen, we know we're callling Class.forName with existing classes

            }

        }

        // in case no apropriate stack trace element was found, just return the most deepest one
        return stackTrace[stackTrace.length-1];
    }

    public static void logExceptionElement(Throwable exception){
        StackTraceElement element = getTopLevelFunction(exception);
        System.err.println(String.format("Exception in class %s, method %s, line %d",
                element.getClass().getName(),
                element.getMethodName(),
                element.getLineNumber(),
                exception.getMessage()
                ));

    }

    public static void main(String[] args) {
        StackTrace test = new StackTrace();


        try{
            test.getCredentials();
        }
        catch (RuntimeException err){
            // should log "getCredentials()" as top level function exception point
            logExceptionElement(err);
        }


        try{
            test.getName();
        }
        catch (RuntimeException err){
            // should log "getName()" as top level function exception point
            logExceptionElement(err);
        }

    }

}

然而,仅仅为了记录目的而对整个代码进行注释可能会很痛苦。但是,您可以重用一些现有的注释,例如,基于 Spring 的数据库应用程序可以跟踪堆栈中的第一个“事务”方法。其他分析方法可能涉及跳过 getter(任何以“get”开头的方法)、按名称/包名称跳过某些类等。

关于java - 如何在Exception的stackTrace中找到自己编码的类或过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8047005/

相关文章:

java - 如何在一段时间后打开另一个窗口?

java - 空对象引用上的 FFmpeg.execute.FFmpegExecuteResponseHandler

c# - 静态 C# 对象导致 : COM object that has been separated from its underlying RCW cannot be used

java - "duck an exception"是什么意思?

Java异常处理理解问题

java - 关于 request.getParameter 和 JSTL

java - 从方法中获取两种不同类型的数据和结构

java - jsp/servlet 中的 session 中的值为空

c++ - 调用 SDL_RenderCopy 时出现异常

java - 如果 ViewModel 类的 minifyEnabled 为 true,则出现 RuntimeException