¿Cómo podemos imprimir números de línea en el inicio de sesión de Java?


132

Cómo imprimir números de línea en el registro. Digamos que al enviar alguna información al registro, también quiero imprimir el número de línea donde está esa salida en el código fuente. Como podemos ver en el seguimiento de la pila, muestra el número de línea donde se produjo la excepción. El seguimiento de pila está disponible en el objeto de excepción.

Otra alternativa podría ser la inclusión manual del número de línea al imprimir en el registro. ¿Hay alguna otra manera?


44
¡vea la respuesta subestimada de @Juan a continuación para una breve y dulce frase! acabo de renunciar a 15 puntos de representante rechazando todas las demás respuestas: v y votando a Juan's
nigromante

Respuestas:


102

De Angsuman Chakraborty :

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

55
Esto siempre devolverá el número de línea de la declaración de devolución en el método llamado y no necesariamente el número de línea de la llamada al método.
Ron Tuffin

¿No [2] obtiene el marco de arriba getLineNumber ()? ([1] siendo getLineNumber (), y [0] siendo getStackTrace (), presumiblemente)
Simon Buchan

1
Jugué un poco y si usa blah.getStackTrace [3] .getLineNumber () como el cuerpo del método, devuelve el número de línea de donde se llamó el método.
Ron Tuffin

12
El índice cambiará según la versión de JVM. Creo que cambió de 1.4 a 1.5.
Ed Thomas

2
Hola @SimonBuchan, el chico tiene nombre :) Escribí ese artículo hace mucho tiempo.
Angsuman Chakraborty

74

Terminamos usando una clase personalizada como esta para nuestro trabajo con 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
Hola Michael, gracias por tu solución, está funcionando bien para mí mostrar los números de línea para la información de registro ... gracias de nuevo. Espero sus excelentes soluciones en Android.
sathish

3
Investigaría un poco más sobre este código antes de usarlo; cuando publiqué el código, getStackTrace () [3] funcionó. Puede depender de la versión de Android o JVM, o algún otro factor.
Michael Baltaks

3
esta respuesta no funciona no muestra la línea y nombre de la clase y el nombre de la función de la clase DebugLog no hay línea de la persona que llama de otra clase
Rahul

@Rahul debería ser en getStackTrace()[3]lugar degetStackTrace()[2]
user5480949

@ user5480949: Use "new Throwable (). getStackTrace ()" para obtener un índice coherente para su función de llamada, independientemente de JVM. (En lugar de Thread.currentThread (). GetStackTrace ())
Luc Bloom

36

Manera rápida y sucia:

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

Con algunos detalles más:

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

Eso generará algo como esto:

com.example.mytest.MyClass/myMethod:103

1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);me da todos los detalles que necesito :)
nigromante

Tenga en cuenta que no se garantiza que la JVM proporcione un seguimiento de pila donde esto sea correcto. Tampoco creo que Hotspot haga esa garantía (pero sus stacktraces son normalmente correctos).
Thorbjørn Ravn Andersen

muy limpio, clase StackTraceElement l = new Exception (). getStackTrace () [1]; trabaja conmigo
vuhung3990

@ ThorbjørnRavnAndersen: Use "new Throwable (). GetStackTrace ()" para obtener un índice coherente para su función de llamada, independientemente de JVM. (En lugar de Thread.currentThread (). GetStackTrace ())
Luc Bloom

@LucBloom en los viejos tiempos no se garantizaba que un seguimiento de la pila fuera exacto.
Thorbjørn Ravn Andersen

25

Me veo obligado a responder al no responder a su pregunta. Supongo que está buscando el número de línea únicamente para admitir la depuración. Hay mejores formas Hay formas difíciles de obtener la línea actual. Todo lo que he visto son lentos. Es mejor usar un marco de registro como ese en java.util.logging package o log4j . Con estos paquetes, puede configurar su información de registro para incluir el contexto hasta el nombre de la clase. Luego, cada mensaje de registro sería lo suficientemente único como para saber de dónde vino. Como resultado, su código tendrá una variable 'logger' a la que llama a través de

logger.debug("a really descriptive message")

en vez de

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


15

Log4J le permite incluir el número de línea como parte de su patrón de salida. Consulte http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html para obtener detalles sobre cómo hacer esto (el elemento clave en el patrón de conversión es "L"). Sin embargo, el Javadoc incluye lo siguiente:

ADVERTENCIA La generación de información sobre la ubicación de la persona que llama es extremadamente lenta. Se debe evitar su uso a menos que la velocidad de ejecución no sea un problema.


El mecanismo subyacente se ha vuelto mucho más rápido en las versiones más recientes de la JVM, pero aún debe usarse con moderación.
Thorbjørn Ravn Andersen

7

El código publicado por @ simon.buchan funcionará ...

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

Pero si lo llama en un método, siempre devolverá el número de línea de la línea en el método, así que use el fragmento de código en línea.


Supuse que el '2' era obtener el número de línea del llamador getLineNumber ().
Simon Buchan

@ simon.buchan: edite su respuesta (según mi último comentario). No quiero robar tu representante por tu respuesta.
Ron Tuffin

O cambie el 2 a otro número. Dependiendo de qué tan profundo esté anidado.
clankill3r

7

Recomendaría usar un kit de herramientas de registro como log4j . El registro se puede configurar a través de archivos de propiedades en tiempo de ejecución, y puede activar / desactivar funciones como el número de línea / registro de nombre de archivo.

Mirar el javadoc para PatternLayout te da la lista completa de opciones: lo que buscas es% L.


7

Utilizo este pequeño método que genera el rastreo y el número de línea del método que lo llamó.

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

¡Haga doble clic en la salida para ir a esa línea de código fuente!

Es posible que deba ajustar el valor del nivel dependiendo de dónde coloque su código.

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

1
¿De dónde Utilviene esto ?
Benj

@benj Utils es solo una clase general sobre la que tienes control. Puede poner el método en cualquier clase (tenga en cuenta que el método es estático).
Sydwell

1
OK, solo quería estar seguro. Gracias por este buen código.
Benj

1

No puede garantizar la coherencia del número de línea con el código, especialmente si está compilado para su lanzamiento. De todos modos, no recomendaría usar números de línea para ese propósito, sería mejor dar una carga útil del lugar donde se produjo la excepción (el método trivial es configurar el mensaje para incluir los detalles de la llamada al método).

Es posible que desee ver el enriquecimiento de excepciones como una técnica para mejorar el manejo de excepciones http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html


0

Si se ha compilado para su lanzamiento, esto no es posible. Es posible que desee analizar algo como Log4J, que le dará automáticamente suficiente información para determinar de cerca dónde se produjo el código registrado.


0

primero el método general (en una clase de utilidad, en el código java1.4 simple, puede que tenga que reescribirlo para java1.5 y más)

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

Luego, el método de utilidad específico para obtener el stackElement correcto:

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

Mira este enlace . En ese método, puede saltar a su código de línea, cuando hace doble clic en la fila de LogCat.

También puede usar este código para obtener el número de línea:

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

Todos estos le brindan los números de línea de su hilo y método actual que funcionan muy bien si usa un try catch donde espera una excepción. Pero si desea detectar cualquier excepción no controlada, está utilizando el controlador de excepción no capturado predeterminado y el subproceso actual devolverá el número de línea de la función de controlador, no el método de clase que arrojó la excepción. En lugar de usar Thread.currentThread () simplemente use el Throwable pasado por el controlador de excepciones:

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

En lo anterior, use e.getStackTrace () [0] en su función de controlador (fShowUncaughtMessage) para obtener el delincuente.


0

El siguiente código es el código probado para la línea de registro sin nombre de clase y nombre de método desde donde se llama al método de registro

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

El stackLeveldepende de la profundidad se llama a este método. Puede probar de 0 a un gran número para ver qué diferencia.

Si stackLeveles legal, obtendrá una cadena comojava.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

Esta es exactamente la característica que implementé en esta lib XDDLib . (Pero es para Android)

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

ingrese la descripción de la imagen aquí

Un clic en el texto subrayado para navegar hacia donde está el comando de registro

Eso StackTraceElementestá determinado por el primer elemento fuera de esta biblioteca. Por lo tanto, en cualquier lugar fuera de esta lib será legal, incluyendo lambda expression, static initialization block, etc.


-1

A mi manera me funciona

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.