Как мы можем напечатать номера строк в журнале на java

133

Как вывести номера строк в журнал. Скажем, при выводе некоторой информации в журнал я также хочу напечатать номер строки, где этот вывод находится в исходном коде. Как мы видим на трассировке стека, он отображает номер строки, в которой произошло исключение. Трассировка стека доступна для объекта исключения.

Другой альтернативой может быть включение вручную номера строки при печати в журнал. Есть ли другой путь?

Бобби Кумар
источник
4
см. недооцененный ответ @Juan ниже, чтобы получить короткий и милый однострочник! я просто отказался от 15 очков репутации, голосуя против всех остальных ответов: v и голосуя за Хуана
некроманта

Ответы:

102

От Ангсумана Чакраборти :

/** Get the current line number.
 * @return int - Current line number.
 */
public static int getLineNumber() {
    return Thread.currentThread().getStackTrace()[2].getLineNumber();
}
Саймон Бьюкен
источник
5
Это всегда будет возвращать номер строки оператора return в вызываемом методе, а не обязательно номер строки вызова метода.
Рон Таффин,
Разве [2] не получает фрейм выше getLineNumber ()? ([1] - это getLineNumber (), а [0] - это, вероятно, getStackTrace ())
Саймон Бьюкен,
1
Я немного поигрался, и если вы используете blah.getStackTrace [3] .getLineNumber () в качестве тела метода, он возвращает номер строки, в которой был вызван метод.
Рон Таффин,
12
Индекс будет меняться в зависимости от версии JVM. Я считаю, что он изменился с 1,4 на 1,5.
Эд Томас
2
Привет, @SimonBuchan, у этого парня есть имя :) Я написал эту статью давно.
Ангсуман Чакраборти,
74

В итоге мы использовали такой настраиваемый класс для работы с 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
Привет, Майкл, спасибо за ваше решение, у меня отлично работает отображение номеров строк для информации журнала .... еще раз спасибо. Я с нетерпением жду ваших замечательных решений в android.
sathish
3
Я бы еще немного изучил этот код, прежде чем использовать его - когда я опубликовал код, getStackTrace () [3] работал. Это может зависеть от версии Android или JVM или какого-либо другого фактора.
Майкл Балтакс
3
этот ответ не работает, он показывает номер строки, имя класса и имя функции класса DebugLog, а не строку номера вызывающего абонента из другого класса
Рахул,
@Rahul это должно быть getStackTrace()[3]вместоgetStackTrace()[2]
user5480949 08
@ user5480949: используйте «new Throwable (). getStackTrace ()», чтобы получить согласованный индекс для вызывающей функции, независимо от JVM. (Вместо Thread.currentThread (). GetStackTrace ())
Люк Блум
36

Быстрый и грязный способ:

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

С некоторыми подробностями:

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

Это выведет что-то вроде этого:

com.example.mytest.MyClass/myMethod:103
Juan
источник
1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);дает мне все необходимые детали :)
necromancer
Обратите внимание, что JVM не гарантирует получение трассировки стека там, где это правильно. Я не верю, что Hotspot дает такую ​​гарантию (но трассировки стека обычно верны).
Торбьёрн Равн Андерсен
очень чистый, класс StackTraceElement l = new Exception (). getStackTrace () [1]; работай со мной
vuhung3990
@ ThorbjørnRavnAndersen: используйте «new Throwable (). GetStackTrace ()», чтобы получить согласованный индекс для вашей вызывающей функции, независимо от JVM. (Вместо Thread.currentThread (). GetStackTrace ())
Люк Блум,
@LucBloom Раньше вам не гарантировали точность трассировки стека.
Thorbjørn Ravn Andersen
25

Я вынужден ответить, не отвечая на ваш вопрос. Я предполагаю, что вы ищете номер строки исключительно для поддержки отладки. Есть лучшие способы. Есть хакерские способы получить текущую строку. Все, что я видел, медленные. Лучше использовать фреймворк журналирования, подобный тому, что есть в пакете java.util.logging или log4j . Используя эти пакеты, вы можете настроить информацию для ведения журнала, чтобы включить контекст вплоть до имени класса. Тогда каждое сообщение журнала будет достаточно уникальным, чтобы знать, откуда оно пришло. В результате в вашем коде будет переменная logger, которую вы вызываете через

logger.debug("a really descriptive message")

вместо того

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

Джеймс А. Уилсон
источник
15

Log4J позволяет включать номер строки как часть шаблона вывода. См. Http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html для получения подробной информации о том, как это сделать (ключевой элемент в шаблоне преобразования - «L»). Однако Javadoc включает следующее:

ПРЕДУПРЕЖДЕНИЕ. Создание информации о местонахождении вызывающего абонента происходит очень медленно. Его использования следует избегать, если только скорость выполнения не является проблемой.

Джим Кили
источник
Базовый механизм стал намного быстрее в более поздних версиях JVM, но его по-прежнему следует использовать с осторожностью.
Торбьёрн Равн Андерсен
7

Код, опубликованный @ simon.buchan, будет работать ...

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

Но если вы вызываете его в методе, он всегда будет возвращать номер строки в методе, поэтому лучше используйте встроенный фрагмент кода.

Рон Туффин
источник
Я предположил, что «2» - это номер строки вызывающей функции getLineNumber ().
Саймон Бьюкен,
@ simon.buchan - отредактируйте свой ответ (согласно моему последнему комментарию). Я не хочу красть вашу репутацию за ваш ответ.
Рон Таффин,
Или измените 2 на другое число. В зависимости от того, насколько глубоко он вложен.
clankill3r
7

Я бы рекомендовал использовать набор инструментов для ведения журнала, например log4j . Ведение журнала можно настроить с помощью файлов свойств во время выполнения, и вы можете включить / выключить такие функции, как ведение журнала номера строки / имени файла.

Глядя на javadoc для PatternLayout, вы получите полный список опций - вам нужен % L.


источник
7

Я использую этот небольшой метод, который выводит трассировку и номер строки метода, который его вызвал.

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

Дважды щелкните вывод, чтобы перейти к этой строке исходного кода!

Вам может потребоваться отрегулировать значение уровня в зависимости от того, где вы разместили свой код.

public static String lineOut() {
    int level = 3;
    StackTraceElement[] traces;
    traces = Thread.currentThread().getStackTrace();
    return (" at "  + traces[level] + " " );
}
Sydwell
источник
1
Откуда это Utilвзялось?
Benj
@benj Utils - это просто общий класс, которым вы можете управлять. Вы можете поместить метод в любой класс (обратите внимание, что метод статический).
Sydwell
1
Хорошо, я просто хотел убедиться. Спасибо за этот красивый фрагмент кода.
Benj
1

Вы не можете гарантировать согласованность номеров строк с кодом, особенно если он скомпилирован для выпуска. В любом случае я бы не рекомендовал использовать номера строк для этой цели, было бы лучше указать полезную нагрузку места, где было возбуждено исключение (тривиальный метод - установить сообщение, включающее детали вызова метода).

Возможно, вам захочется взглянуть на обогащение исключений как на метод улучшения обработки исключений http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html

UberAlex
источник
0

Если он был скомпилирован для выпуска, это невозможно. Возможно, вы захотите изучить что-то вроде Log4J, которое автоматически предоставит вам достаточно информации, чтобы довольно точно определить, где произошел записанный код.

GBA
источник
0

сначала общий метод (в служебном классе, хотя в простом старом коде java1.4 вам, возможно, придется переписать его для java1.5 и более)

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

Затем специальный служебный метод для получения правильного 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;
  }
VonC
источник
0

Посмотри по этой ссылке . В этом методе вы можете перейти к своему строковому коду, дважды щелкнув строку LogCat.

Также вы можете использовать этот код для получения номера строки:

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
источник
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

Все они дают вам номера строк вашего текущего потока и метода, которые отлично работают, если вы используете try catch там, где вы ожидаете исключения. Но если вы хотите перехватить какое-либо необработанное исключение, тогда вы используете обработчик неперехваченных исключений по умолчанию, и текущий поток вернет номер строки функции обработчика, а не метод класса, вызвавший исключение. Вместо использования Thread.currentThread () просто используйте Throwable, переданный обработчиком исключений:

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

В приведенном выше примере используйте e.getStackTrace () [0] в своей функции-обработчике (fShowUncaughtMessage), чтобы поймать нарушителя.

отметка
источник
0

Ниже показан проверенный код для строки журнала без имени класса и имени метода, откуда вызывается метод ведения журнала.

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

Это stackLevelзависит от глубины, на которой вы вызываете этот метод. Вы можете попробовать от 0 до большого числа, чтобы увидеть, в чем разница.

Если stackLevelэто законно, вы получите строку видаjava.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
источник
0

Это именно та функция, которую я реализовал в этой библиотеке XDDLib . (Но это для android)

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

введите описание изображения здесь

Один щелчок по подчеркнутому тексту позволяет перейти туда, где находится команда журнала.

Это StackTraceElementопределяется первым элементом вне этой библиотеки. Таким образом, в любом месте за пределами этой библиотеки будет законным, в том числе lambda expression, static initialization blockи т.д.

Оуэн Чен
источник
-1

Мой способ работает для меня

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
источник
-1

вы можете использовать -> Reporter.log ("");

рутвей гусани
источник