Como podemos imprimir números de linha para o log em java

132

Como imprimir números de linha no log. Digamos que ao enviar algumas informações para o log, também quero imprimir o número da linha em que essa saída está no código-fonte. Como podemos ver no rastreamento da pilha, ele exibe o número da linha em que a exceção ocorreu. O rastreamento de pilha está disponível no objeto de exceção.

Outra alternativa pode ser como incluir manualmente o número da linha ao imprimir no log. Existe alguma outra maneira?

Bobby Kumar
fonte
4
veja a resposta subestimada de @ Juan abaixo para uma breve e doce frase de apresentação! eu desisti 15 pontos rep downvoting todas as outras respostas: v e upvoting de Juan
necromante

Respostas:

102

De Angsuman Chakraborty :

/** Get the current line number.
 * @return int - Current line number.
 */
public static int getLineNumber() {
    return Thread.currentThread().getStackTrace()[2].getLineNumber();
}
Simon Buchan
fonte
5
Isso sempre retornará o número da linha da instrução de retorno no método chamado e não necessariamente o número da linha da chamada do método.
Ron Tuffin 22/09/08
O [2] não obtém o quadro acima de getLineNumber ()? ([1] sendo getLineNumber () e [0] sendo getStackTrace (), presumivelmente))
Simon Buchan
1
Eu brinquei um pouco e se você usar blah.getStackTrace [3] .getLineNumber () como o corpo do método, ele retornará o número da linha de onde o método foi chamado.
Ron Tuffin 22/09/08
12
O índice será alterado com base na versão da JVM. Eu acredito que mudou de 1.4 para 1.5.
Ed Thomas
2
Hey @SimonBuchan, o cara tem um nome :) Eu escrevi esse artigo há muito tempo.
Angsuman Chakraborty
74

Acabamos usando uma classe personalizada como esta para o nosso trabalho 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);
  }
 }
}
Michael Baltaks
fonte
1
Olá Michael, obrigado por sua solução, está funcionando bem para eu exibir os números de linha para informações de log .... obrigado novamente. Estou ansioso por suas ótimas soluções no Android.
sathish 12/01
3
Eu faria mais algumas pesquisas sobre esse código antes de usá-lo - quando publiquei o código, getStackTrace () [3] funcionou. Pode depender da versão do Android ou JVM ou de algum outro fator.
precisa saber é o seguinte
3
esta resposta não funciona mostra nenhuma linha e nome da classe e nome da função de classe DebugLog não linha não de chamador de outra classe
Rahul
@Rahul que deveria ser getStackTrace()[3], em vez degetStackTrace()[2]
user5480949
@ user5480949: Use "new Throwable (). getStackTrace ()" para obter um índice consistente para sua função de chamada, independentemente da JVM. (Em vez de Thread.currentThread () getStackTrace ().)
Luc Bloom
36

Maneira rápida e suja:

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

Com mais alguns detalhes:

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

Isso produzirá algo como isto:

com.example.mytest.MyClass/myMethod:103
Juan
fonte
1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);me dá todos os detalhes que eu preciso :)
necromante
Observe que a JVM não tem garantia de fornecer um rastreamento de pilha onde isso estiver correto. Também não acredito que o Hotspot faça essa garantia (mas seus rastreamentos de pilha estão normalmente corretos).
Thorbjørn Ravn Andersen 29/10
muito limpo, classe StackTraceElement l = new Exception (). getStackTrace () [1]; trabalha comigo
vuhung3990 7/15/15
@ ThorbjørnRavnAndersen: Use "new Throwable (). GetStackTrace ()" para obter um índice consistente para a sua função de chamada, independentemente da JVM. (Em vez de Thread.currentThread (). GetStackTrace ())
Luc Bloom
@LucBloom Antigamente, não era garantido que um rastreamento de pilha era preciso.
Thorbjørn Ravn Andersen
25

Sou obrigado a responder por não responder à sua pergunta. Suponho que você esteja procurando o número da linha apenas para oferecer suporte à depuração. Existem maneiras melhores. Existem maneiras hackeadas de obter a linha atual. Tudo que eu vi é lento. É melhor usar uma estrutura de log como a do pacote java.util.logging ou log4j . Usando esses pacotes, você pode configurar suas informações de log para incluir o contexto até o nome da classe. Cada mensagem de log seria única o suficiente para saber de onde veio. Como resultado, seu código terá uma variável 'logger' que você chama por

logger.debug("a really descriptive message")

ao invés de

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

James A Wilson
fonte
15

O Log4J permite incluir o número da linha como parte de seu padrão de saída. Consulte http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html para obter detalhes sobre como fazer isso (o elemento-chave no padrão de conversão é "L"). No entanto, o Javadoc inclui o seguinte:

AVISO A geração de informações de localização do chamador é extremamente lenta. Seu uso deve ser evitado, a menos que a velocidade de execução não seja um problema.

Jim Kiley
fonte
O mecanismo subjacente tornou-se muito mais rápido nas versões mais recentes da JVM, mas ainda deve ser usado com moderação.
Thorbjørn Ravn Andersen 29/10
7

O código postado por @ simon.buchan funcionará ...

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

Mas se você chamá-lo em um método, ele sempre retornará o número da linha no método; portanto, use o snippet de código inline.

Ron Tuffin
fonte
Imaginei que o '2' era obter o número da linha do chamador getLineNumber ().
Simon Buchan
@ simon.buchan - edite sua resposta (conforme meu último comentário). Não quero roubar seu representante para obter sua resposta.
Ron Tuffin 22/09/08
Ou mude o 2 para outro número. Dependendo da profundidade do aninhamento.
precisa saber é o seguinte
7

Eu recomendaria o uso de um kit de ferramentas de log, como o log4j . O log é configurável por meio de arquivos de propriedades em tempo de execução, e você pode ativar / desativar recursos como log de número de linha / nome de arquivo.

Examinar o javadoc para o PatternLayout fornece uma lista completa de opções - o que você procura é% L.


fonte
7

Eu uso esse pequeno método que gera o número de rastreamento e linha do método que o chamou.

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

Clique duas vezes na saída para ir para a linha de código-fonte!

Pode ser necessário ajustar o valor do nível, dependendo de onde você colocou seu código.

public static String lineOut() {
    int level = 3;
    StackTraceElement[] traces;
    traces = Thread.currentThread().getStackTrace();
    return (" at "  + traces[level] + " " );
}
Sydwell
fonte
1
De onde isso Utilvem?
precisa
O @benj Utils é apenas uma classe geral sobre a qual você tem controle. Você pode colocar o método em qualquer classe (observe que o método é estático).
Sydwell
1
OK, eu só queria ter certeza. Obrigado por este belo pedaço de código.
Ben
1

Você não pode garantir a consistência do número da linha com o código, especialmente se ele for compilado para liberação. Eu não recomendaria o uso de números de linha para esse fim, seria melhor fornecer uma carga útil do local em que a exceção foi gerada (o método trivial é definir a mensagem para incluir os detalhes da chamada do método).

Você pode considerar o aprimoramento de exceção como uma técnica para melhorar o tratamento de exceções http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html

UberAlex
fonte
0

Se foi compilado para lançamento, isso não é possível. Você pode procurar algo como o Log4J, que fornecerá automaticamente informações suficientes para determinar de perto onde o código registrado ocorreu.

GBa
fonte
0

primeiro o método geral (em uma classe de utilitário, no código java1.4 antigo e simples, talvez seja necessário reescrevê-lo para java1.5 e mais)

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

Em seguida, o método utilitário específico para obter o stackElement correto:

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

Veja este link . Nesse método, você pode pular para o seu código de linha quando clicar duas vezes na linha do LogCat.

Além disso, você pode usar este código para obter o número da linha:

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;
}
Bobs
fonte
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();
}
Raymond
fonte
0

Tudo isso fornece os números de linha do seu segmento e método atuais, que funcionam muito bem se você usar uma tentativa de tentar onde espera uma exceção. Mas se você deseja capturar qualquer exceção não tratada, está usando o manipulador de exceção não capturado padrão e o thread atual retornará o número da linha da função do manipulador, não o método de classe que lançou a exceção. Em vez de usar Thread.currentThread (), basta usar o Throwable transmitido pelo manipulador de exceções:

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

No exemplo acima, use e.getStackTrace () [0] em sua função de manipulador (fShowUncaughtMessage) para obter o agressor.

Marca
fonte
0

O código abaixo é um código testado para a linha de log, nenhum nome de classe e nome do método de onde o método de log é chamado

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;
}
}
Rahul
fonte
0

O stackLeveldepende de profundidade que você chamar esse método. Você pode tentar de 0 a um número grande para ver a diferença.

Se stackLevelfor legal, você receberá uma string 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);
}
Loyea
fonte
0

Esse é exatamente o recurso que implementei nesta lib XDDLib . (Mas, é para android)

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

insira a descrição da imagem aqui

Um clique no texto sublinhado para navegar para onde o comando log está

Isso StackTraceElementé determinado pelo primeiro elemento fora desta biblioteca. Assim, em qualquer lugar fora deste lib vai ser legal, incluindo lambda expression, static initialization block, etc.

Owen Chen
fonte
-1

Meu jeito que funciona para mim

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;
  }
EmiDemi
fonte
-1

você pode usar -> Reporter.log ("");

rutvij gusani
fonte