Как найти код класса или процедуры самостоятельно в stackTrace Исключения - PullRequest
0 голосов
/ 08 ноября 2011

Я кодирую функцию журнала ошибок.
Поэтому мне нужно зарегистрировать некоторую информацию, такую ​​как operator, operator_time, error_message и api_name, для которой CLASS или PROCEDURE будет выдано исключение.
Моя проблема в том, что я не знаюкак получить api_name в java.
Часть трассировки стека исключения (я скрываю название моей компании):

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)' получает имя класса исключения.
Как его кодировать? Большое спасибо.

Ответы [ 2 ]

2 голосов
/ 08 ноября 2011

Процедура, после которой выдает , исключение - первое в стеке. Однако, если я правильно понял ваш вопрос, вы хотите пропустить нерелевантные методы и записать какой-либо значимый метод в журнал ошибок.

Однако, это может быть не так тривиально. Если у вас есть метод "getUserCredentials ()", который вызывает "getUserName ()", который вызывает "getDatabaseConnection ()", который вызывает "connect ()", который вызывает исключение - какой метод должен регистрироваться, когда вы вызываете " getUserCredentials () "? Какой метод должен быть зарегистрирован, когда вы вызываете "getUserCredentials ()" в "generateReport ()", который был вызван в "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 может отслеживать первый «транзакционный» метод в стеке. Другие методы анализа могут включать пропуск методов получения (любые методы, начинающиеся с «get»), пропуск определенных классов по имени / имени пакета и т. Д.

0 голосов
/ 08 ноября 2011

Если вы действительно хотите получить доступ к информации в трассировке стека, вы можете использовать Throwable # getStackTrace () , а затем искать строку после saveErrorLog.

getStackTrace () возвращает массив StackTraceElement , который содержит необходимую информацию.

Я не знаю, как вы вызываете эти методы, но лучшим вариантом было бы передать имя API оттуда, откуда вы вызываете это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...