2013-07-04 15 views
24

Gibt es eine Möglichkeit in Java, die aktuelle Zeilennummer durch Reflexion oder eine tolle API dynamisch zu bekommen? Genau wie wenn Ausnahmen auftreten, wird die Zeilennummer in dem Stack-Trace wie folgt ausgedruckt:Dynamisch erhalten Sie die aktuelle Zeilennummer

at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348) 

Jetzt ist es eine Möglichkeit, wie im folgenden Code zu drucken oder melden Sie sich?

Sie können fragen, warum drucke ich nicht einfach die Zeilennummer? Nun, da der Code möglicherweise vor dem Aufruf der Methode log.error() gelöscht oder hinzugefügt wird.

+2

Ist PatternLayout der Protokollierung APIs nicht praktisch für dieses? – sadhu

+0

Sie könnten ein 'neues Throwable' erstellen und auf die Stack-Trace-Elemente zugreifen. Siehe http://stackoverflow.com/questions/115008/how-can-we-print-line-numbers-to-the-log-in-java –

+2

@Andreas: Sie brauchen kein 'Throwable': [' Thread.getStackTrace() '] (http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#getStackTrace()) ist ausreichend. –

Antwort

7

Ich konnte die Thread.currentThread() verwenden getStackTrace() Methode einen Satz von Funktionen zu schaffen, die zusammenarbeiten, um die Zeilennummer des Codes zu erzeugen, die das erste Verfahren genannt wird, in etwa so:.

/** @return The line number of the code that ran this method 
* @author Brian_Entei */ 
public static int getLineNumber() { 
    return ___8drrd3148796d_Xaf(); 
} 

/** This methods name is ridiculous on purpose to prevent any other method 
* names in the stack trace from potentially matching this one. 
* 
* @return The line number of the code that called the method that called 
*   this method(Should only be called by getLineNumber()). 
* @author Brian_Entei */ 
private static int ___8drrd3148796d_Xaf() { 
    boolean thisOne = false; 
    int thisOneCountDown = 1; 
    StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 
    for(StackTraceElement element : elements) { 
     String methodName = element.getMethodName(); 
     int lineNum = element.getLineNumber(); 
     if(thisOne && (thisOneCountDown == 0)) { 
      return lineNum; 
     } else if(thisOne) { 
      thisOneCountDown--; 
     } 
     if(methodName.equals("___8drrd3148796d_Xaf")) { 
      thisOne = true; 
     } 
    } 
    return -1; 
} 

Hoffe, das hilft! Ich lege diese in eine Utility-Klasse, so dass sie aus dem Weg sind, aber immer noch leicht zugänglich. Die zweite Methode ist privat, um zu verhindern, dass eine andere Methode als die erste Methode sie aufruft, so dass sie immer korrekt funktioniert.

+0

Gute Eins, Diese sollte die akzeptierte Antwort sein. –

34

Sie können eine Throwable erstellen und verwenden seine StackTraceElements:

System.err.println(new Throwable().getStackTrace()[0].getLineNumber()); 

Wie @Joachim sagte, können Sie auch Thread.getStackTrace() verwenden, z.B. wie

System.err.println(Thread.currentThread().getStackTrace()[1].getLineNumber()); 

Beachten Sie, dass der zweite Ansatz eine etwas andere Array zurückgibt - Sie das Array-Element mit dem Index 1 zu erhalten, die aktuellen Zeilennummer verwenden müssen, da es sich um den Anruf zu getStackTrace() sich als erste enthält Element.

Beachten Sie auch die Kommentare zu Protokollierung und Leistung von @ Joachim Antwort.

+1

Kann zu unterschiedlichen Ergebnissen führen auf einigen JVMs. Zumindest auf IBM JVM für AIX enthielt der Stapel die ausführbaren Konstruktoren. Siehe javadoc von getStackTrace: 'Das nullte Element des Arrays (unter der Annahme, dass die Länge des Arrays nicht Null ist) stellt den Anfang des Stapels dar, der der letzte Methodenaufruf in der Sequenz ist. In der Regel ist dies der Punkt, an dem dieser Wurfgegenstand erstellt und geworfen wurde. - In der Regel nicht garantiert. Brian_Enteis Lösung ist also widerstandsfähiger. –

15

Zunächst einmal: Wenn irgendetwas, dann das Logging-Muster (oder Layouter, oder was auch immer Ihre Logging-Framework diesen Teil nennt) sollte dies tun. Der Logger-Aufruf in Ihrem Code sollte nur die tatsächlichen Geschäftsinformationen schreiben. Informationen darüber, wo der Logger hinzufügen soll.

Als nächstes: diese Art von Operation ist teuer (in Bezug auf die Zeit), weil Java nicht dafür optimiert ist. Zur Laufzeit muss die JVM ihren Status prüfen, Debug-Informationen laden/parsen und die einer gegebenen Anweisung entsprechende Zeilennummer finden. Aus diesem Grund wird diese Art von Information normalerweise nur gegeben, wenn eine Ausnahme auftritt (in diesem Fall haben wir bereits ein Problem und wissen,, dass die verbrachte Zeit in der Regel es wert ist).

Und last but not least: wenn aus irgendeinem Grund, dass die Informationen auf eigene Faust, dann können Sie Thread.getStackTrace() verwenden und die zweite StackTraceElement auf sie inspizieren.

0

Man kann auch die Exception-Zeilennummer mit folgendem Code-Schnipsel bekommen. Verwenden Sie die folgende util-Methode in Ihrer util-Klasse.

public static int getExceptionLineNumber(Exception e, String methodNameExp) 
{ 
    StackTraceElement ele = Arrays.stream(e.getStackTrace()).filter(o -> o.getMethodName().equals(methodNameExp)).findAny().orElse(null); 
    if(ele != null){ 
     return ele.getLineNumber(); 
    } 
    return -1; 
} 

Von catch-Block Sie wie unten anrufen:

das funktioniert
catch (Exception e){ 
     logger.info("Exception line number "+ Util.getExceptionLineNumber(e, new Object(){}.getClass().getEnclosingMethod().getName())); 
    } 

Hoffnung! :)

Verwandte Themen