Jak możemy wydrukować numery wierszy do dziennika w java


135

Jak wydrukować numery wierszy w dzienniku. Powiedz, wypisując pewne informacje do dziennika, chcę również wydrukować numer wiersza, w którym te dane wyjściowe znajdują się w kodzie źródłowym. Jak widać w śladzie stosu, wyświetla numer linii, w której wystąpił wyjątek. W obiekcie wyjątku dostępne jest śledzenie stosu.

Inną alternatywą może być ręczne dodawanie numeru linii podczas drukowania do dziennika. Czy jest inny sposób?


4
zobacz niedocenioną odpowiedź @ Juana poniżej, aby uzyskać krótki i słodki jeden liniowiec! Właśnie straciłem 15 punktów rep, odrzucając wszystkie inne odpowiedzi: v i upvoting Juan's
necromancer.

Odpowiedzi:


103

Z Angsuman Chakraborty :

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

6
To zawsze zwróci numer linii instrukcji return w wywołanej metodzie i niekoniecznie numer linii wywołania metody.
Ron Tuffin,

Czy [2] nie pobiera ramki powyżej getLineNumber ()? ([1] jest getLineNumber () i [0] jest getStackTrace (), przypuszczalnie)
Simon Buchan,

1
Bawiłem się trochę i jeśli użyjesz blah.getStackTrace [3] .getLineNumber () jako treści metody, zwraca numer wiersza, w którym metoda została wywołana.
Ron Tuffin,

13
Indeks zmieni się w zależności od wersji maszyny JVM. Myślę, że zmieniło się z 1,4 na 1,5.
Ed Thomas,

2
Hej @SimonBuchan, Facet ma imię :) Napisałem ten artykuł dawno temu.
Angsuman Chakraborty

74

Skończyło się na tym, że użyliśmy niestandardowej klasy, takiej jak ta do naszej pracy na Androida:

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
Cześć Michael, dziękuję za twoje rozwiązanie, działa dobrze, gdybym wyświetlał numery wierszy dla informacji dziennika ... jeszcze raz dziękuję. Z niecierpliwością czekam na Twoje świetne rozwiązania w Androidzie.
satish

3
Zrobiłbym więcej badań nad tym kodem przed jego użyciem - kiedy opublikowałem kod, getStackTrace () [3] zadziałało. Może to zależeć od wersji Androida lub JVM lub innego czynnika.
Michael Baltaks

3
ta odpowiedź nie działa, pokazuje numer linii i nazwę klasy oraz nazwę funkcji klasy DebugLog, a nie numer linii dzwoniącego z innej klasy
Rahul

@Rahul powinno być getStackTrace()[3]zamiastgetStackTrace()[2]
user5480949

@ user5480949: Użyj "new Throwable (). getStackTrace ()", aby uzyskać spójny indeks dla funkcji wywołującej, niezależnie od maszyny JVM. (Zamiast Thread.currentThread () getStackTrace ().)
Luc Bloom

36

Szybki i brudny sposób:

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

Więcej szczegółów:

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

To wyświetli coś takiego:

com.example.mytest.MyClass/myMethod:103

1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);podaje mi wszystkie szczegóły, których potrzebuję :)
nekromanta

Zwróć uwagę, że JVM nie gwarantuje, że da ślad stosu, jeśli jest to poprawne. Nie wierzę, że Hotspot też to gwarantuje (ale jego ślady stosu są zwykle poprawne).
Thorbjørn Ravn Andersen

bardzo czysty, klasa StackTraceElement l = new Exception (). getStackTrace () [1]; pracuj ze mną
vuhung3990,

@ ThorbjørnRavnAndersen: Użyj "new Throwable (). GetStackTrace ()", aby uzyskać spójny indeks dla funkcji wywołującej, niezależnie od JVM. (Zamiast Thread.currentThread (). GetStackTrace ())
Luc Bloom

@LucBloom W dawnych czasach nie miałeś gwarancji, że ślad stosu jest dokładny.
Thorbjørn Ravn Andersen

25

Jestem zmuszony odpowiedzieć, nie odpowiadając na twoje pytanie. Zakładam, że szukasz numeru linii wyłącznie do obsługi debugowania. Są lepsze sposoby. Istnieją hakerskie sposoby na uzyskanie aktualnej linii. Wszystko, co widziałem, jest powolne. Lepiej jest używać struktury rejestrowania, takiej jak w pakiecie java.util.logging lub log4j . Korzystając z tych pakietów, możesz skonfigurować informacje logowania, aby uwzględnić kontekst aż do nazwy klasy. Wtedy każdy komunikat dziennika byłby na tyle unikalny, aby wiedzieć, skąd pochodzi. W rezultacie Twój kod będzie zawierał zmienną „logger”, którą wywołujesz

logger.debug("a really descriptive message")

zamiast

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


15

Log4J umożliwia dołączenie numeru linii jako części wzoru wyjściowego. Zobacz http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html, aby dowiedzieć się, jak to zrobić (kluczowym elementem we wzorcu konwersji jest „L”). Jednak Javadoc zawiera następujące elementy:

OSTRZEŻENIE Generowanie informacji o lokalizacji dzwoniącego jest bardzo wolne. Jego użycia należy unikać, chyba że szybkość wykonywania nie jest problemem.


Podstawowy mechanizm stał się znacznie szybszy w nowszych wersjach JVM, ale nadal powinien być używany oszczędnie.
Thorbjørn Ravn Andersen

7

Kod wysłany przez @ simon.buchan zadziała ...

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

Ale jeśli wywołasz go w metodzie, zawsze zwróci numer wiersza w metodzie, więc raczej użyj wbudowanego fragmentu kodu.


Domyślam się, że cyfra „2” służyła do uzyskania numeru linii wywołującego getLineNumber ().
Simon Buchan,

@ simon.buchan - edytuj swoją odpowiedź (zgodnie z moim ostatnim komentarzem). Nie chcę kraść twojej reputacji za twoją odpowiedź.
Ron Tuffin

Lub zmień 2 na inną liczbę. W zależności od tego, jak głęboko jest zagnieżdżony.
clankill3r

7

Polecam użycie zestawu narzędzi do rejestrowania, takiego jak log4j . Rejestrowanie można konfigurować za pomocą plików właściwości w czasie wykonywania i można włączać / wyłączać takie funkcje, jak rejestrowanie numeru linii / nazwy pliku.

Spojrzenie na javadoc dla PatternLayout daje Ci pełną listę opcji - szukasz% L.


7

Używam tej małej metody, która wyświetla ślad i numer wiersza metody, która ją wywołała.

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

Kliknij dwukrotnie dane wyjściowe, aby przejść do tej linii kodu źródłowego!

Może zajść potrzeba dostosowania wartości poziomu w zależności od tego, gdzie umieściłeś kod.

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

1
Skąd to się Utilbierze?
Benj

@benj Utils to tylko ogólna klasa, nad którą masz kontrolę. Możesz umieścić metodę w dowolnej klasie (zwróć uwagę, że metoda jest statyczna).
Sydwell,

1
OK, chciałem się tylko upewnić. Dzięki za ten niezły fragment kodu.
Benj

1

Nie możesz zagwarantować spójności numeru wiersza z kodem, zwłaszcza jeśli jest on kompilowany do wydania. I tak nie polecałbym używania w tym celu numerów linii, lepiej byłoby podać ładunek miejsca, w którym wystąpił wyjątek (trywialną metodą jest ustawienie komunikatu tak, aby zawierał szczegóły wywołania metody).

Możesz spojrzeć na wzbogacanie wyjątków jako technikę poprawy obsługi wyjątków http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html


0

Jeśli został skompilowany do wydania, nie jest to możliwe. Możesz zajrzeć do czegoś takiego jak Log4J, które automatycznie dostarczy ci wystarczających informacji, aby dość dokładnie określić, gdzie pojawił się zarejestrowany kod.


0

najpierw ogólna metoda (w klasie narzędziowej, chociaż w zwykłym starym kodzie java1.4 może być konieczne przepisanie go na java1.5 i więcej)

/**
 * 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;
}

Następnie konkretna metoda narzędziowa, aby uzyskać odpowiedni stackElement:

/**
   * 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

Spójrz na ten link . W tej metodzie możesz przeskoczyć do kodu linii, klikając dwukrotnie wiersz LogCat.

Możesz również użyć tego kodu, aby uzyskać numer linii:

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

To wszystko daje ci numery wierszy twojego aktualnego wątku i metody, która działa świetnie, jeśli używasz try catch tam, gdzie spodziewasz się wyjątku. Ale jeśli chcesz przechwycić jakikolwiek nieobsługiwany wyjątek, używasz domyślnej procedury obsługi nieprzechwyconego wyjątku, a bieżący wątek zwróci numer wiersza funkcji obsługi, a nie metodę klasy, która spowodowała wyrzucenie wyjątku. Zamiast używać Thread.currentThread () po prostu użyj Throwable przekazanego przez procedurę obsługi wyjątków:

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

W powyższym przykładzie użyj e.getStackTrace () [0] w swojej funkcji obsługi (fShowUncaughtMessage), aby pobrać sprawcę.


0

Poniższy kod jest testowanym kodem dla linii logowania bez nazwy klasy i nazwy metody, z której jest wywoływana metoda logowania

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

stackLevelZależy od głębokości wywołać tę metodę. Możesz spróbować od 0 do dużej liczby, aby zobaczyć, jaka jest różnica.

Jeśli stackLeveljest to legalne, otrzymasz ciąg podobny dojava.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

To jest dokładnie ta funkcja, którą zaimplementowałem w tej bibliotece XDDLib . (Ale to dla Androida)

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

wprowadź opis obrazu tutaj

Jedno kliknięcie podkreślonego tekstu, aby przejść do miejsca, w którym znajduje się polecenie dziennika

Która StackTraceElementjest określana przez pierwszy element spoza tej biblioteki. Tak więc, gdziekolwiek poza tym lib będzie prawnym, w tym lambda expression, static initialization blockitp


0

Dla każdego, kto się zastanawia, indeks w getStackTrace()[3]metodzie sygnalizuje liczbę wątków pokonywanych przez linię wyzwalającą, aż do faktycznej metody .getStackTrace () z wyłączeniem linii wykonawczej.

Oznacza to, że jeśli Thread.currentThread().getStackTrace()[X].getLineNumber();wiersz jest wykonywany z 3 metod zagnieżdżonych powyżej , numer indeksu musi wynosić 3 .

Przykład:

Pierwsza warstwa

private static String message(String TAG, String msg) {

    int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();

    return ".(" + TAG + ".java:"+ lineNumber +")" + " " + msg;
}

Druga warstwa

private static void print(String s) {
        System.out.println(s);
}

Trzecia warstwa

public static void normal(
        String TAG,
        String message
) {
    print(
            message(
                    TAG,
                    message
            )
    );
}

Wykonywanie linii:

    Print.normal(TAG, "StatelessDispatcher");

Jako osoba, która nie otrzymała żadnego formalnego wykształcenia w zakresie IT, otworzyła umysł na temat działania kompilatorów.


-1

Mój sposób to działa dla mnie

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;
  }

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.