Come possiamo stampare i numeri di riga sul log in java


133

Come stampare i numeri di riga nel registro. Di 'quando invii alcune informazioni al registro, voglio anche stampare il numero di riga dove si trova quell'output nel codice sorgente. Come possiamo vedere nella traccia dello stack, visualizza il numero di riga in cui si è verificata l'eccezione. La traccia dello stack è disponibile sull'oggetto eccezione.

Altre alternative potrebbero essere come includere manualmente il numero di riga quando si stampa sul registro. C'è un altro modo?


4
vedi la risposta sottovalutata di @ Juan sotto per una breve e dolce battuta! ho appena rinunciato a 15 punti rappresentante votando a fondo tutte le altre risposte: v e votando Juan's
negromante

Risposte:


102

Da Angsuman Chakraborty :

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

5
Ciò restituirà sempre il numero di riga dell'istruzione return nel metodo chiamato e non necessariamente il numero di riga della chiamata al metodo.
Ron Tuffin,

Il [2] non ottiene il frame sopra getLineNumber ()? ([1] essendo getLineNumber () e [0] essendo getStackTrace (), presumibilmente)
Simon Buchan,

1
Ho giocato un po 'in giro e se usi blah.getStackTrace [3] .getLineNumber () come corpo del metodo, restituisce il numero di riga del metodo chiamato.
Ron Tuffin,

12
L'indice cambierà in base alla versione JVM. Credo che sia cambiato da 1.4 a 1.5.
Ed Thomas,

2
Ehi @SimonBuchan, il ragazzo ha un nome :) Ho scritto quell'articolo molto tempo fa.
Angsuman Chakraborty,

74

Abbiamo finito per utilizzare una classe personalizzata come questa per il nostro lavoro su Android:

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
Ciao Michael, grazie per la tua soluzione, sta funzionando bene per me per visualizzare i numeri di riga per le informazioni del registro .... grazie ancora. Non vedo l'ora di trovare le tue fantastiche soluzioni su Android.
sathish il

3
Farei qualche altra ricerca su questo codice prima di usarlo - quando ho pubblicato il codice, getStackTrace () [3] ha funzionato. Potrebbe dipendere dalla versione di Android o JVM o da qualche altro fattore.
Michael Baltaks,

3
questa risposta non funziona mostra la linea no e il nome della classe e il nome della funzione della classe DebugLog non la linea no del chiamante di un'altra classe
Rahul

@Rahul dovrebbe essere getStackTrace()[3]invece digetStackTrace()[2]
user5480949

@ user5480949: utilizzare "new Throwable (). getStackTrace ()" per ottenere un indice coerente per la funzione di chiamata, indipendentemente da JVM. (Invece di Thread.currentThread (). GetStackTrace ())
Luc Bloom,

36

Modo rapido e sporco:

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

Con qualche dettaglio in più:

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

Questo produrrà qualcosa del genere:

com.example.mytest.MyClass/myMethod:103

1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);mi dà tutti i dettagli di cui ho bisogno :)
Negromante

Si noti che non è garantito che JVM fornisca uno stacktrace in cui ciò è corretto. Non credo che sia Hotspot a garantire (ma i suoi stack stack sono normalmente corretti).
Thorbjørn Ravn Andersen,

molto pulito, classe StackTraceElement l = new Exception (). getStackTrace () [1]; lavora con me
vuhung3990

@ ThorbjørnRavnAndersen: utilizzare "new Throwable (). GetStackTrace ()" per ottenere un indice coerente per la funzione di chiamata, indipendentemente da JVM. (Invece di Thread.currentThread (). GetStackTrace ())
Luc Bloom,

@LucBloom ai vecchi tempi non ti era garantito che una traccia dello stack fosse accurata.
Thorbjørn Ravn Andersen,

25

Sono costretto a rispondere non rispondendo alla tua domanda. Suppongo che tu stia cercando il numero di riga solo per supportare il debug. Ci sono modi migliori. Ci sono modi hacker per ottenere la linea corrente. Tutto quello che ho visto sono lenti. È meglio utilizzare un framework di registrazione come quello nel pacchetto java.util.logging o log4j . Utilizzando questi pacchetti è possibile configurare le informazioni di registrazione per includere il contesto fino al nome della classe. Quindi ogni messaggio di registro sarebbe abbastanza unico da sapere da dove proveniva. Di conseguenza, il tuo codice avrà una variabile 'logger' che chiami

logger.debug("a really descriptive message")

invece di

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


15

Log4J consente di includere il numero di riga come parte del suo modello di output. Vedi http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html per i dettagli su come farlo (l'elemento chiave nel modello di conversione è "L"). Tuttavia, Javadoc include quanto segue:

ATTENZIONE La generazione delle informazioni sulla posizione del chiamante è estremamente lenta. L'uso dovrebbe essere evitato a meno che la velocità di esecuzione non sia un problema.


Il meccanismo sottostante è diventato molto più veloce nelle versioni più recenti di JVM, ma dovrebbe comunque essere usato con parsimonia.
Thorbjørn Ravn Andersen,

7

Il codice pubblicato da @ simon.buchan funzionerà ...

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

Ma se lo chiami in un metodo restituirà sempre il numero di riga della linea nel metodo, quindi usa piuttosto lo snippet di codice in linea.


Immaginavo che "2" fosse quello di ottenere il numero di linea del chiamante getLineNumber ().
Simon Buchan,

@ simon.buchan - modifica la tua risposta (come da mio ultimo commento). Non voglio rubare il tuo rappresentante per la tua risposta.
Ron Tuffin,

Oppure cambia il 2 in un altro numero. A seconda della profondità della nidificazione.
clankill3r,

7

Consiglierei di usare un toolkit di registrazione come log4j . La registrazione è configurabile tramite i file delle proprietà in fase di esecuzione ed è possibile attivare / disattivare funzionalità come la registrazione del numero di riga / nome file.

Guardando il javadoc per PatternLayout ti dà l'elenco completo delle opzioni - quello che stai cercando è% L.


7

Uso questo piccolo metodo che genera la traccia e il numero di riga del metodo che lo ha chiamato.

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

Fare doppio clic sull'output per passare alla riga del codice sorgente!

Potrebbe essere necessario regolare il valore del livello in base a dove è stato inserito il codice.

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

1
Da dove Utilviene?
Benj,

@benj Utils è solo una classe generale su cui hai il controllo. È possibile inserire il metodo in qualsiasi classe (notare che il metodo è statico).
Sydwell,

1
OK, volevo solo esserne sicuro. Grazie per questo bel po 'di codice.
Benj,

1

Non è possibile garantire la coerenza del numero di riga con il codice, soprattutto se viene compilato per il rilascio. Non consiglierei comunque di utilizzare i numeri di riga a tale scopo, sarebbe meglio fornire un payload del luogo in cui è stata sollevata l'eccezione (il metodo banale è impostare il messaggio in modo da includere i dettagli della chiamata del metodo).

Potresti considerare l'arricchimento delle eccezioni come una tecnica per migliorare la gestione delle eccezioni http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html


0

Se è stato compilato per il rilascio, questo non è possibile. Potresti voler esaminare qualcosa come Log4J che ti fornirà automaticamente informazioni sufficienti per determinare abbastanza da vicino dove si è verificato il codice registrato.


0

prima il metodo generale (in una classe di utilità, nel semplice vecchio codice java1.4, tuttavia, potrebbe essere necessario riscriverlo per java1.5 e altro)

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

Quindi il metodo di utilità specifico per ottenere lo stackElement giusto:

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

Guarda questo link . In quel metodo puoi saltare al tuo codice di linea, quando fai doppio clic sulla riga di LogCat.

Inoltre puoi usare questo codice per ottenere il numero di riga:

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

Tutti questi ti danno i numeri di riga del thread e del metodo correnti che funzionano alla grande se usi un tentativo try dove ti aspetti un'eccezione. Ma se si desidera rilevare un'eccezione non gestita, si sta utilizzando il gestore eccezioni non rilevate predefinito e il thread corrente restituirà il numero di riga della funzione del gestore, non il metodo di classe che ha generato l'eccezione. Invece di usare Thread.currentThread () usa semplicemente il Throwable passato dal gestore delle eccezioni:

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

In quanto sopra usa e.getStackTrace () [0] nella tua funzione di gestore (fShowUncaughtMessage) per ottenere l'autore del reato.


0

Sotto il codice viene testato il codice per la riga di registrazione senza nome classe e nome metodo da cui viene chiamato il metodo di registrazione

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

La stackLeveldipende profondità si chiama questo metodo. Puoi provare da 0 a un numero elevato per vedere quale differenza.

Se stackLevelè legale, otterrai stringhe comejava.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

Questa è esattamente la funzione che ho implementato in questa libreria XDDLib . (Ma è per Android)

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

inserisci qui la descrizione dell'immagine

Un clic sul testo sottolineato per passare a dove si trova il comando di registro

Ciò StackTraceElementè determinato dal primo elemento esterno a questa libreria. Così, ovunque fuori dal lib sarà legale, tra cui lambda expression, static initialization block, ecc


-1

A modo mio funziona per me

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.