Wie können wir Zeilennummern in das Protokoll in Java drucken?


132

So drucken Sie Zeilennummern in das Protokoll. Wenn Sie beispielsweise einige Informationen in das Protokoll ausgeben, möchte ich auch die Zeilennummer drucken, in der sich diese Ausgabe im Quellcode befindet. Wie wir im Stack-Trace sehen können, wird die Zeilennummer angezeigt, in der die Ausnahme aufgetreten ist. Für das Ausnahmeobjekt ist eine Stapelverfolgung verfügbar.

Eine andere Alternative könnte das manuelle Einfügen der Zeilennummer beim Drucken in das Protokoll sein. Gibt es einen anderen Weg?


4
Siehe @ Juans unterschätzte Antwort unten für einen kurzen und süßen Einzeiler! Ich habe gerade 15 Punkte aufgegeben und alle anderen Antworten abgelehnt: v und Juan's
Nekromanten

Antworten:


102

Von Angsuman Chakraborty :

/** Get the current line number.
 * @return int - Current line number.
 */
public static int getLineNumber() {
    return Thread.currentThread().getStackTrace()[2].getLineNumber();
}

5
Dies gibt immer die Zeilennummer der return-Anweisung in der aufgerufenen Methode zurück und nicht unbedingt die Zeilennummer des Methodenaufrufs.
Ron Tuffin

Bekommt der [2] nicht den Frame über getLineNumber ()? ([1] ist vermutlich getLineNumber () und [0] ist getStackTrace ())
Simon Buchan

1
Ich habe ein bisschen herumgespielt und wenn Sie blah.getStackTrace [3] .getLineNumber () als Methodenkörper verwenden, wird die Zeilennummer zurückgegeben, in der die Methode aufgerufen wurde.
Ron Tuffin

12
Der Index ändert sich basierend auf der JVM-Version. Ich glaube, es hat sich von 1,4 auf 1,5 geändert.
Ed Thomas

2
Hey @SimonBuchan, der Typ hat einen Namen :) Ich habe diesen Artikel vor langer Zeit geschrieben.
Angsuman Chakraborty

74

Am Ende haben wir eine benutzerdefinierte Klasse wie diese für unsere Android-Arbeit verwendet:

import android.util.Log;    
public class DebugLog {
 public final static boolean DEBUG = true;    
 public static void log(String message) {
  if (DEBUG) {
    String fullClassName = Thread.currentThread().getStackTrace()[2].getClassName();
    String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
    String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
    int lineNumber = Thread.currentThread().getStackTrace()[2].getLineNumber();

    Log.d(className + "." + methodName + "():" + lineNumber, message);
  }
 }
}

1
Hallo Michael, danke für deine Lösung, es funktioniert gut für mich, die Zeilennummern für Protokollinformationen anzuzeigen .... nochmals vielen Dank. Ich freue mich auf Ihre tollen Lösungen in Android.
Sathish

3
Ich würde diesen Code vor der Verwendung genauer untersuchen - als ich den Code veröffentlichte, funktionierte getStackTrace () [3]. Dies kann von der Version von Android oder JVM oder einem anderen Faktor abhängen.
Michael Baltaks

3
Diese Antwort funktioniert nicht. Sie zeigt die Zeilennummer und den Klassennamen und den Funktionsnamen der DebugLog-Klasse, nicht die Zeilennummer des Anrufers einer anderen Klasse
Rahul,

@ Rahul sollte es getStackTrace()[3]statt seingetStackTrace()[2]
user5480949

@ user5480949: Verwenden Sie "new Throwable (). getStackTrace ()", um einen konsistenten Index für Ihre aufrufende Funktion zu erhalten, unabhängig von der JVM. (Anstelle von Thread.currentThread (). GetStackTrace ())
Luc Bloom

36

Schneller und schmutziger Weg:

System.out.println("I'm in line #" + 
    new Exception().getStackTrace()[0].getLineNumber());

Mit einigen weiteren Details:

StackTraceElement l = new Exception().getStackTrace()[0];
System.out.println(
    l.getClassName()+"/"+l.getMethodName()+":"+l.getLineNumber());

Das wird ungefähr so ​​ausgeben:

com.example.mytest.MyClass/myMethod:103

1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);gibt mir alle Details, die ich brauche :)
Nekromant

Beachten Sie, dass die JVM nicht garantiert einen Stacktrace liefert, wenn dies korrekt ist. Ich glaube auch nicht, dass Hotspot diese Garantie übernimmt (aber die Stacktraces sind normalerweise korrekt).
Thorbjørn Ravn Andersen

sehr sauber, Klasse StackTraceElement l = neue Ausnahme (). getStackTrace () [1]; arbeite mit mir
vuhung3990

@ ThorbjørnRavnAndersen: Verwenden Sie "new Throwable (). GetStackTrace ()", um unabhängig von der JVM einen konsistenten Index für Ihre aufrufende Funktion zu erhalten. (Anstelle von Thread.currentThread (). GetStackTrace ())
Luc Bloom

@LucBloom In den alten Tagen wurde Ihnen nicht garantiert, dass eine Stapelverfolgung korrekt war.
Thorbjørn Ravn Andersen

25

Ich bin gezwungen zu antworten, indem ich Ihre Frage nicht beantworte. Ich gehe davon aus, dass Sie die Zeilennummer nur zur Unterstützung des Debuggens suchen. Es gibt bessere Wege. Es gibt hackige Möglichkeiten, um die aktuelle Zeile zu erhalten. Ich habe nur langsam gesehen. Sie sind besser dran, wenn Sie ein Protokollierungsframework wie das in java.util.logging-Paket oder log4j verwenden . Mit diesen Paketen können Sie Ihre Protokollierungsinformationen so konfigurieren, dass sie den Kontext bis zum Klassennamen enthalten. Dann wäre jede Protokollnachricht eindeutig genug, um zu wissen, woher sie stammt. Infolgedessen enthält Ihr Code eine 'Logger'-Variable, über die Sie aufrufen

logger.debug("a really descriptive message")

anstatt

System.out.println("a really descriptive message")


15

Mit Log4J können Sie die Zeilennummer als Teil des Ausgabemusters einschließen. Weitere Informationen hierzu finden Sie unter http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html (das Schlüsselelement im Konvertierungsmuster ist "L"). Der Javadoc enthält jedoch Folgendes:

WARNUNG Das Generieren von Anruferstandortinformationen ist extrem langsam. Die Verwendung sollte vermieden werden, es sei denn, die Ausführungsgeschwindigkeit spielt keine Rolle.


Der zugrunde liegende Mechanismus ist in neueren Versionen der JVM viel schneller geworden, sollte jedoch weiterhin sparsam eingesetzt werden.
Thorbjørn Ravn Andersen

7

Der von @ simon.buchan gepostete Code funktioniert ...

Thread.currentThread().getStackTrace()[2].getLineNumber()

Wenn Sie es jedoch in einer Methode aufrufen, wird immer die Zeilennummer der Zeile in der Methode zurückgegeben. Verwenden Sie daher lieber das Code-Snippet inline.


Ich vermutete, dass die '2' die Zeilennummer des Aufrufers getLineNumber () erhalten sollte.
Simon Buchan

@ simon.buchan - bearbeite deine Antwort (gemäß meinem letzten Kommentar). Ich möchte Ihren Repräsentanten nicht für Ihre Antwort stehlen.
Ron Tuffin

Oder ändern Sie die 2 in eine andere Zahl. Je nachdem wie tief es verschachtelt ist.
Clankill3r

7

Ich würde empfehlen, ein Protokollierungs-Toolkit wie log4j zu verwenden . Die Protokollierung kann zur Laufzeit über Eigenschaftendateien konfiguriert werden, und Sie können Funktionen wie die Protokollierung von Zeilennummer / Dateiname aktivieren / deaktivieren.

Wenn Sie sich das Javadoc für das PatternLayout ansehen, erhalten Sie die vollständige Liste der Optionen - was Sie suchen, ist% L.


7

Ich benutze diese kleine Methode, die den Trace und die Zeilennummer der Methode ausgibt, die sie aufgerufen hat.

 Log.d(TAG, "Where did i put this debug code again?   " + Utils.lineOut());

Doppelklicken Sie auf die Ausgabe, um zu dieser Quellcodezeile zu gelangen!

Möglicherweise müssen Sie den Pegelwert anpassen, je nachdem, wo Sie Ihren Code ablegen.

public static String lineOut() {
    int level = 3;
    StackTraceElement[] traces;
    traces = Thread.currentThread().getStackTrace();
    return (" at "  + traces[level] + " " );
}

1
Woher kommt das Util?
Benj

@benj Utils ist nur eine allgemeine Klasse, über die Sie die Kontrolle haben. Sie können die Methode in eine beliebige Klasse einfügen (beachten Sie, dass die Methode statisch ist).
Sydwell

1
OK, ich wollte nur sicher sein. Danke für diesen schönen Code.
Benj

1

Sie können die Konsistenz der Zeilennummern mit dem Code nicht garantieren, insbesondere wenn er für die Freigabe kompiliert wurde. Ich würde sowieso nicht empfehlen, Zeilennummern für diesen Zweck zu verwenden. Es wäre besser, eine Nutzlast des Ortes anzugeben, an dem die Ausnahme ausgelöst wurde (die triviale Methode besteht darin, die Nachricht so einzustellen, dass sie die Details des Methodenaufrufs enthält).

Vielleicht möchten Sie die Anreicherung von Ausnahmen als eine Technik zur Verbesserung der Ausnahmebehandlung betrachten. Http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html


0

Wenn es für die Veröffentlichung kompiliert wurde, ist dies nicht möglich. Vielleicht möchten Sie sich etwas wie Log4J ansehen, das Ihnen automatisch genügend Informationen liefert, um ziemlich genau zu bestimmen, wo der protokollierte Code aufgetreten ist.


0

Zuerst die allgemeine Methode (in einer Utility-Klasse, in einfachem alten Java1.4-Code, müssen Sie sie möglicherweise für Java1.5 und mehr neu schreiben).

/**
 * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
 * Allows to get past a certain class.
 * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
 * @return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
 */
public static String getClassMethodLine(final Class aclass)  {
    final StackTraceElement st = getCallingStackTraceElement(aclass);
    final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
    +")] <" + Thread.currentThread().getName() + ">: ";
    return amsg;
}

Dann die spezifische Dienstprogrammmethode, um das richtige stackElement zu erhalten:

/**
   * Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
   * Stored in array of the callstack. <br />
   * Allows to get past a certain class.
   * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
   * @return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
   * @throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
   */
  public static StackTraceElement getCallingStackTraceElement(final Class aclass) {
    final Throwable           t         = new Throwable();
    final StackTraceElement[] ste       = t.getStackTrace();
    int index = 1;
    final int limit = ste.length;
    StackTraceElement   st        = ste[index];
    String              className = st.getClassName();
    boolean aclassfound = false;
    if(aclass == null) {
        aclassfound = true;
    }
    StackTraceElement   resst = null;
    while(index < limit) {
        if(shouldExamine(className, aclass) == true) {
            if(resst == null) {
                resst = st;
            }
            if(aclassfound == true) {
                final StackTraceElement ast = onClassfound(aclass, className, st);
                if(ast != null) {
                    resst = ast;
                    break;
                }
            }
            else
            {
                if(aclass != null && aclass.getName().equals(className) == true) {
                    aclassfound = true;
                }
            }
        }
        index = index + 1;
        st        = ste[index];
        className = st.getClassName();
    }
    if(isNull(resst))  {
        throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
    }
    return resst;
  }

  static private boolean shouldExamine(String className, Class aclass) {
      final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith(LOG_UTILS
        ) == false || (aclass !=null && aclass.getName().endsWith(LOG_UTILS)));
      return res;
  }

  static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st) {
      StackTraceElement   resst = null;
      if(aclass != null && aclass.getName().equals(className) == false)
      {
          resst = st;
      }
      if(aclass == null)
      {
          resst = st;
      }
      return resst;
  }


0

Schauen Sie sich diesen Link an . Bei dieser Methode können Sie zu Ihrem Zeilencode springen, wenn Sie auf die Zeile von LogCat doppelklicken.

Sie können diesen Code auch verwenden, um die Zeilennummer abzurufen:

public static int getLineNumber()
{
    int lineNumber = 0;
    StackTraceElement[] stackTraceElement = Thread.currentThread()
            .getStackTrace();
    int currentIndex = -1;
    for (int i = 0; i < stackTraceElement.length; i++) {
        if (stackTraceElement[i].getMethodName().compareTo("getLineNumber") == 0)
        {
            currentIndex = i + 1;
            break;
        }
    }

    lineNumber = stackTraceElement[currentIndex].getLineNumber();

    return lineNumber;
}

0
private static final int CLIENT_CODE_STACK_INDEX;

static {
    // Finds out the index of "this code" in the returned stack Trace - funny but it differs in JDK 1.5 and 1.6
    int i = 0;
    for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
        i++;
        if (ste.getClassName().equals(Trace.class.getName())) {
            break;
        }
    }
    CLIENT_CODE_STACK_INDEX = i;
}

private String methodName() {
    StackTraceElement ste=Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX+1];
    return ste.getMethodName()+":"+ste.getLineNumber();
}

0

Mit diesen Informationen erhalten Sie die Zeilennummern Ihres aktuellen Threads und Ihrer aktuellen Methode, die hervorragend funktionieren, wenn Sie einen Try-Catch verwenden, bei dem Sie eine Ausnahme erwarten. Wenn Sie jedoch eine nicht behandelte Ausnahme abfangen möchten, verwenden Sie den Standardhandler für nicht erfasste Ausnahmen, und der aktuelle Thread gibt die Zeilennummer der Handlerfunktion zurück, nicht die Klassenmethode, die die Ausnahme ausgelöst hat. Anstatt Thread.currentThread () zu verwenden, verwenden Sie einfach das vom Ausnahmebehandler übergebene Throwable:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable e) {              
                if(fShowUncaughtMessage(e,t))               
                    System.exit(1);
            }
        });

Verwenden Sie oben e.getStackTrace () [0] in Ihrer Handlerfunktion (fShowUncaughtMessage), um den Täter zu ermitteln.


0

Der folgende Code enthält den getesteten Code für die Protokollierungszeile, keinen Klassennamen und Methodennamen, von dem aus die Protokollierungsmethode aufgerufen wird

public class Utils {
/*
 * debug variable enables/disables all log messages to logcat
 * Useful to disable prior to app store submission
 */
public static final boolean debug = true;

/*
 * l method used to log passed string and returns the
 * calling file as the tag, method and line number prior
 * to the string's message
 */
public static void l(String s) {
    if (debug) {
        String[] msg = trace(Thread.currentThread().getStackTrace(), 3);
        Log.i(msg[0], msg[1] + s);
    } else {
        return;
    }
}

/*
 * l (tag, string)
 * used to pass logging messages as normal but can be disabled
 * when debug == false
 */
public static void l(String t, String s) {
    if (debug) {
        Log.i(t, s);
    } else {
        return;
    }
}

/*
 * trace
 * Gathers the calling file, method, and line from the stack
 * returns a string array with element 0 as file name and 
 * element 1 as method[line]
 */
public static String[] trace(final StackTraceElement e[], final int level) {
    if (e != null && e.length >= level) {
        final StackTraceElement s = e[level];
        if (s != null) { return new String[] {
                e[level].getFileName(), e[level].getMethodName() + "[" + e[level].getLineNumber() + "]"
        };}
    }
    return null;
}
}

0

Das stackLevelhängt von der Tiefe ab, die Sie diese Methode nennen. Sie können von 0 bis zu einer großen Zahl versuchen, um festzustellen, welcher Unterschied besteht.

Wenn stackLeveles legal ist, erhalten Sie einen String wiejava.lang.Thread.getStackTrace(Thread.java:1536)

public static String getCodeLocationInfo(int stackLevel) {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        if (stackLevel < 0 || stackLevel >= stackTraceElements.length) {
            return "Stack Level Out Of StackTrace Bounds";
        }
        StackTraceElement stackTraceElement = stackTraceElements[stackLevel];
        String fullClassName = stackTraceElement.getClassName();
        String methodName = stackTraceElement.getMethodName();
        String fileName = stackTraceElement.getFileName();
        int lineNumber = stackTraceElement.getLineNumber();

        return String.format("%s.%s(%s:%s)", fullClassName, methodName, fileName, lineNumber);
}

0

Dies ist genau die Funktion, die ich in dieser lib XDDLib implementiert habe . (Aber es ist für Android)

Lg.d("int array:", intArrayOf(1, 2, 3), "int list:", listOf(4, 5, 6))

Geben Sie hier die Bildbeschreibung ein

Klicken Sie mit einem Klick auf den unterstrichenen Text , um zu der Stelle zu navigieren, an der sich der Protokollbefehl befindet

Das StackTraceElementwird durch das erste Element außerhalb dieser Bibliothek bestimmt. So wird überall außerhalb dieser lib legal sein, einschließlich lambda expression, static initialization blockusw.


-1

So wie es bei mir funktioniert

String str = "select os.name from os where os.idos="+nameid;  try {
        PreparedStatement stmt = conn.prepareStatement(str);
        ResultSet rs = stmt.executeQuery();
        if (rs.next()) {
            a = rs.getString("os.n1ame");//<<<----Here is the ERROR          
        }
        stmt.close();
  } catch (SQLException e) {
        System.out.println("error line : " + e.getStackTrace()[2].getLineNumber());            
        return a;
  }

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.