Comment pouvons-nous imprimer les numéros de ligne dans le journal en Java


133

Comment imprimer les numéros de ligne dans le journal. Dites lors de la sortie de certaines informations dans le journal, je veux également imprimer le numéro de ligne où cette sortie est dans le code source. Comme nous pouvons le voir dans la trace de la pile, il affiche le numéro de ligne où l'exception s'est produite. La trace de pile est disponible sur l'objet d'exception.

Une autre alternative pourrait consister à inclure manuellement le numéro de ligne lors de l'impression dans le journal. Est-ce qu'il y a un autre moyen?


4
voir la réponse sous-estimée de @ Juan ci-dessous pour une courte et douce ligne! Je viens d'abandonner 15 points de représentant en votant contre toutes les autres réponses: v et en faveur de Juan
nécromancien

Réponses:


102

Depuis Angsuman Chakraborty :

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

5
Cela retournera toujours le numéro de ligne de l'instruction return dans la méthode appelée et pas nécessairement le numéro de ligne de l'appel de méthode.
Ron Tuffin le

Le [2] n'obtient-il pas le cadre au-dessus de getLineNumber ()? ([1] étant getLineNumber (), et [0] étant getStackTrace (), vraisemblablement)
Simon Buchan

1
J'ai joué un peu et si vous utilisez blah.getStackTrace [3] .getLineNumber () comme corps de méthode, il renvoie le numéro de ligne de l'endroit où la méthode a été appelée.
Ron Tuffin le

12
L'index changera en fonction de la version JVM. Je crois qu'il est passé de 1,4 à 1,5.
Ed Thomas

2
Salut @SimonBuchan, Le gars a un nom :) J'ai écrit cet article il y a longtemps.
Angsuman Chakraborty

74

Nous avons fini par utiliser une classe personnalisée comme celle-ci pour notre travail sur 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
Salut Michael, merci pour votre solution, cela fonctionne très bien pour moi d'afficher les numéros de ligne pour les informations de journal .... merci encore. J'attends avec impatience vos excellentes solutions sous Android.
sathish

3
Je ferais plus de recherches sur ce code avant de l'utiliser - quand j'ai posté le code, getStackTrace () [3] fonctionnait. Cela peut dépendre de la version d'Android ou de JVM, ou d'un autre facteur.
Michael Baltaks

3
cette réponse ne fonctionne pas, elle affiche le numéro de ligne et le nom de la classe et le nom de la fonction de la classe DebugLog et non le numéro de ligne de l'appelant d'une autre classe
Rahul

@Rahul ça devrait être getStackTrace()[3]au lieu degetStackTrace()[2]
user5480949

@ user5480949: Utilisez "new Throwable (). getStackTrace ()" pour obtenir un index cohérent pour votre fonction appelante, quelle que soit la JVM. (Au lieu de Thread.currentThread (). GetStackTrace ())
Luc Bloom

36

Manière rapide et sale:

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

Avec quelques détails supplémentaires:

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

Cela produira quelque chose comme ceci:

com.example.mytest.MyClass/myMethod:103

1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);me donne tous les détails dont j'ai besoin :)
necromancer

Notez que la machine virtuelle Java n'est pas garantie de donner une trace de pile là où cela est correct. Je ne crois pas que Hotspot offre cette garantie non plus (mais ses traces de pile sont normalement correctes).
Thorbjørn Ravn Andersen

très propre, classe StackTraceElement l = new Exception (). getStackTrace () [1]; travaille avec moi
vuhung3990

@ ThorbjørnRavnAndersen: Utilisez "new Throwable (). GetStackTrace ()" pour obtenir un index cohérent pour votre fonction appelante, quelle que soit la JVM. (Au lieu de Thread.currentThread (). GetStackTrace ())
Luc Bloom

@LucBloom dans l'ancien temps, vous n'étiez pas assuré qu'une trace de pile était précise.
Thorbjørn Ravn Andersen

25

Je suis obligé de répondre en ne répondant pas à votre question. Je suppose que vous recherchez le numéro de ligne uniquement pour prendre en charge le débogage. Il existe de meilleures façons. Il existe des moyens hackers pour obtenir la ligne actuelle. Tout ce que j'ai vu est lent. Il vaut mieux utiliser un cadre de journalisation comme celui du package java.util.logging ou log4j . À l'aide de ces packages, vous pouvez configurer vos informations de journalisation pour inclure le contexte jusqu'au nom de la classe. Ensuite, chaque message de journal serait suffisamment unique pour savoir d'où il vient. En conséquence, votre code aura une variable 'logger' que vous appelez via

logger.debug("a really descriptive message")

au lieu de

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


15

Log4J vous permet d'inclure le numéro de ligne dans son modèle de sortie. Voir http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html pour plus de détails sur la façon de procéder (l'élément clé du modèle de conversion est "L"). Cependant, le Javadoc comprend les éléments suivants:

AVERTISSEMENT La génération des informations de localisation de l'appelant est extrêmement lente. Son utilisation doit être évitée sauf si la vitesse d'exécution n'est pas un problème.


Le mécanisme sous-jacent est devenu beaucoup plus rapide dans les versions plus récentes de la JVM, mais il doit encore être utilisé avec parcimonie.
Thorbjørn Ravn Andersen

7

Le code posté par @ simon.buchan fonctionnera ...

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

Mais si vous l'appelez dans une méthode, il retournera toujours le numéro de ligne de la ligne dans la méthode, utilisez donc plutôt l'extrait de code en ligne.


J'ai deviné que le «2» était d'obtenir le numéro de ligne de l'appelant getLineNumber ().
Simon Buchan

@ simon.buchan - modifiez votre réponse (selon mon dernier commentaire). Je ne veux pas voler votre représentant pour votre réponse.
Ron Tuffin le

Ou changez le 2 en un autre nombre. En fonction de sa profondeur d'imbrication.
clankill3r

7

Je recommanderais d'utiliser une boîte à outils de journalisation telle que log4j . La journalisation est configurable via les fichiers de propriétés lors de l'exécution, et vous pouvez activer / désactiver des fonctionnalités telles que la journalisation des numéros de ligne / nom de fichier.

En regardant le javadoc pour PatternLayout vous donne la liste complète des options - ce que vous recherchez, c'est% L.


7

J'utilise cette petite méthode qui génère la trace et le numéro de ligne de la méthode qui l'a appelée.

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

Double-cliquez sur la sortie pour accéder à cette ligne de code source!

Vous devrez peut-être ajuster la valeur du niveau en fonction de l'endroit où vous placez votre code.

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

1
D'où cela Utilvient-il?
Benj

@benj Utils est juste une classe générale sur laquelle vous avez le contrôle. Vous pouvez placer la méthode dans n'importe quelle classe (notez que la méthode est statique).
Sydwell

1
OK, je voulais juste être sûr. Merci pour ce petit bout de code.
Benj

1

Vous ne pouvez pas garantir la cohérence du numéro de ligne avec le code, surtout s'il est compilé pour la publication. Je ne recommanderais de toute façon pas d'utiliser les numéros de ligne à cette fin, il serait préférable de donner une charge utile de l'endroit où l'exception a été levée (la méthode triviale étant de définir le message pour inclure les détails de l'appel de méthode).

Vous voudrez peut-être considérer l'enrichissement des exceptions comme une technique pour améliorer la gestion des exceptions http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html


0

S'il a été compilé pour la publication, ce n'est pas possible. Vous voudrez peut-être examiner quelque chose comme Log4J qui vous donnera automatiquement suffisamment d'informations pour déterminer assez précisément où le code enregistré s'est produit.


0

d'abord la méthode générale (dans une classe utilitaire, dans un ancien code java1.4, vous devrez peut-être la réécrire pour java1.5 et plus)

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

Ensuite, la méthode utilitaire spécifique pour obtenir le bon 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

Regardez ce lien . Dans cette méthode, vous pouvez accéder à votre code de ligne lorsque vous double-cliquez sur la ligne de LogCat.

Vous pouvez également utiliser ce code pour obtenir le numéro de ligne:

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

Ceux-ci vous donnent tous les numéros de ligne de votre thread actuel et de votre méthode qui fonctionnent très bien si vous utilisez un try catch où vous attendez une exception. Mais si vous voulez attraper une exception non gérée, vous utilisez le gestionnaire d'exceptions non interceptées par défaut et le thread actuel renverra le numéro de ligne de la fonction de gestionnaire, pas la méthode de classe qui a levé l'exception. Au lieu d'utiliser Thread.currentThread (), utilisez simplement le Throwable transmis par le gestionnaire d'exceptions:

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

Dans ce qui précède, utilisez e.getStackTrace () [0] dans votre fonction de gestionnaire (fShowUncaughtMessage) pour obtenir le contrevenant.


0

Le code ci-dessous est un code testé pour la ligne de journalisation sans nom de classe et nom de méthode à partir de laquelle la méthode de journalisation est appelée

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

le stackLevel dépend de la profondeur que vous appelez cette méthode. Vous pouvez essayer de 0 à un grand nombre pour voir quelle différence.

Si stackLevelc'est légal, vous obtiendrez une chaîne commejava.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

C'est exactement la fonctionnalité que j'ai implémentée dans cette lib XDDLib . (Mais c'est pour Android)

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

entrez la description de l'image ici

Un clic sur le texte souligné pour accéder à la commande de journal

Cela StackTraceElementest déterminé par le premier élément en dehors de cette bibliothèque. Ainsi, partout en dehors de cette lib sera légale, y compris lambda expression, static initialization blocketc.


-1

Ma façon dont ça marche pour moi

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.