Як можна друкувати номери рядків до журналу Java


133

Як надрукувати номери рядків до журналу. Скажімо, виводячи деяку інформацію в журнал, я також хочу надрукувати номер рядка, де цей вихід знаходиться у вихідному коді. Як ми бачимо у сліді стека, він відображає номер рядка, де стався виняток. Слід стека доступний для об'єкта виключення.

Інша альтернатива може бути, як вручну, включаючи номер рядка під час друку до журналу. Чи є інший спосіб?


4
див. нижче недооцінену відповідь Хуана на короткий та солодкий однолінійний! я щойно відмовився від 15 балів, відмовившись від усіх інших відповідей: v та підтримка Хуана
некроман

Відповіді:


102

З чакраборті Angsuman :

/** 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 (), імовірно)
Simon Buchan

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.
сатиш

3
Я б ще трохи дослідив цей код перед його використанням - коли я опублікував код, спрацювала getStackTrace () [3]. Це може залежати від версії Android або JVM або якогось іншого фактора.
Майкл Балтакс

3
ця відповідь не працює, вона показує номер рядка та назву класу та назву функції класу DebugLog, а не рядок виклику з іншого класу
Rahul

@Rahul це має бути getStackTrace()[3]замістьgetStackTrace()[2]
user5480949

@ 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

1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);дає мені всі потрібні мені відомості :)
некромант

Зауважте, що JVM не гарантовано надає стек-трек там, де це правильно. Я не вірю, що Hotspot також не дає такої гарантії (але її стек-траси, як правило, є правильними).
Thorbjørn Ravn Andersen

дуже чистий, клас StackTraceElement l = новий виняток (). getStackTrace () [1]; робота зі мною
vuhung3990

@ ThorbjørnRavnAndersen: Використовуйте "новий 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 дозволяє включити номер рядка як частину його вихідного шаблону. Докладні відомості про те, як це зробити (див. Ключовий елемент у шаблоні перетворення "L"), див. У розділі http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html . Однак Javadoc включає в себе наступне:

ПОПЕРЕДЖЕННЯ Генерування інформації про місцезнаходження абонента відбувається надзвичайно повільно. Її використання слід уникати, якщо швидкість виконання не є проблемою.


Основні механізми стали набагато швидшими в останніх версіях JVM, однак його все одно слід використовувати ощадливо.
Thorbjørn Ravn Andersen

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] + " " );
}

1
Звідки це Utilпоходить?
Бендж

@benj Utils - це просто загальний клас, над яким ти маєш контроль. Ви можете розмістити метод у будь-якому класі (зверніть увагу, що метод є статичним).
Сідвелл

1
Гаразд, я просто хотів бути впевненим. Дякую за цей приємний шматочок коду.
Бендж

1

Ви не можете гарантувати узгодженість номера рядка з кодом, особливо якщо він складений для випуску. Я б не рекомендував використовувати номери рядків для цієї мети в будь-якому випадку, було б краще надати корисне навантаження на місце, де було піднято виняток (тривіальний метод полягає у встановленні повідомлення, щоб містити деталі виклику методу).

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


0

Якщо вона складена для випуску, це неможливо. Ви можете розглянути щось на зразок Log4J, що автоматично дасть вам достатньо інформації, щоб досить точно визначити, де відбувся зареєстрований код.


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

Потім конкретний корисний метод для отримання потрібного стекаElement:

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

Подивіться за цим посиланням . У цьому методі ви можете перейти до свого рядкового коду, якщо двічі клацнути рядок 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;
}

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

Всі вони отримують номери рядків вашого поточного потоку та метод, які чудово працюють, якщо ви використовуєте спробу лову, де ви очікуєте винятку. Але якщо ви хочете зловити будь-який не оброблений виняток, тоді ви використовуєте за замовчуванням обробку винятків uncaught і поточний потік поверне номер рядка функції обробника, а не метод класу, який викинув виняток. Замість використання 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);
}

0

Саме ця функція була реалізована в цій lib 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;
  }

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.