如何在Java中将行号打印到日志?

150
如何在日志中打印行号。当输出一些信息到日志时,我也想打印该输出在源代码中的行号。正如我们在堆栈跟踪中所看到的,它显示了异常发生的行号。堆栈跟踪可以在异常对象上获得。
另一种选择是在打印到日志时手动包含行号。是否还有其他方法?

4
请看下面@Juan未受到足够重视的简短回答!我刚刚放弃了15点声望,下投其他所有回答:v并顶起了Juan的。 - necromancer
22个回答

115

来自Angsuman Chakraborty的信息(已存档):

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

7
这将始终返回被调用方法中return语句的行号,而不一定是方法调用的行号。 - Ron Tuffin
1
我稍微尝试了一下,如果你使用blah.getStackTrace[3].getLineNumber()作为方法体,它会返回调用该方法的行号。 - Ron Tuffin
14
索引将根据JVM版本进行更改。我相信它是从1.4更改为1.5。 - Ed Thomas
2
嘿@SimonBuchan,这个人有名字 :) 我很久以前写了那篇文章。 - Angsuman Chakraborty
4
这看起来足够无害,但我想知道getStackTrace()的代价是多少。它似乎过于复杂。我希望有编译器解决方案/宏,可以在编译时硬编码数字,就像c++一样。 不过,这仍然是可用答案中最好的一个。 - Jim
显示剩余5条评论

79

我们最终使用了一个自定义类来完成我们的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
嗨,Michael,感谢你的解决方案,它对我来说可以很好地显示日志信息的行号...再次感谢。我期待着你在Android上的出色解决方案。 - sathish
3
在使用这段代码之前,我建议你进行更多的研究 - 在我发布这段代码时,getStackTrace()[3] 是有效的。但它可能依赖于Android或JVM版本,或其他因素。 - Michael Baltaks
3
这个答案不起作用,它显示了DebugLog类的行号、类名和函数名,而不是其他类中调用者的行号。 - Rahul
1
@Rahul 应该是 getStackTrace()[3] 而不是 getStackTrace()[2] - user5480949
使用 "new Throwable().getStackTrace()" 来获取您调用的函数的一致索引,而不考虑 JVM。 (而不是 Thread.currentThread().getStackTrace()) - Luc Bloom

41

快速并简单的方法:

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("我在这里: " + new Exception().getStackTrace()[0]); 给了我所有我需要的细节 :) - necromancer
请注意,JVM不能保证在正确的情况下提供堆栈跟踪。我不认为Hotspot也会做出这样的保证(但它的堆栈跟踪通常是正确的)。 - Thorbjørn Ravn Andersen
非常干净,类StackTraceElement l = new Exception().getStackTrace()[1]; 与我一起工作。 - vuhung3990
使用 "new Throwable().getStackTrace()" 来获取您调用的函数的一致索引,而不考虑 JVM。 (而不是 Thread.currentThread().getStackTrace()) - Luc Bloom
在旧时代,你不能保证堆栈跟踪的准确性。@LucBloom - Thorbjørn Ravn Andersen
在 Kotlin 中,也可以将其写成一行代码:with(Exception().stackTrace[0]) { println("$className/$methodName:$lineNumber") } - AbstractVoid

25
我不得不通过不回答你的问题来回答它。 我假设您只是想要行号以支持调试。 有更好的方法。 有一些hackish的方法可以获得当前行。 所有我看到的都很慢。 您最好使用像java.util.logging包或log4j中的日志框架。 使用这些包,您可以配置日志信息以包括类名下的上下文。 然后,每个日志消息都足够独特,以知道它来自哪里。 因此,您的代码将具有一个“logger”变量,您可以通过

logger.debug("一个非常描述性的消息")

而不是

System.out.println("一个非常描述性的消息")


16

底层机制在最近的JVM版本中变得更快了,但仍应谨慎使用。 - Thorbjørn Ravn Andersen

7

我建议使用日志记录工具,例如log4j。在运行时,可以通过属性文件配置日志记录,并且您可以打开/关闭功能,例如行号/文件名记录。

查看PatternLayout的javadoc将为您提供完整的选项列表 - 您需要的是%L。


7

@simon.buchan发布的代码将会起作用...

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

但是如果你在一个方法中调用它,它总是会返回该方法中的行号,因此最好直接内联使用代码片段。


我猜 '2' 是为了获取 getLineNumber() 调用者的行号。 - Simon Buchan
@simon.buchan - 根据我的最后一条评论,编辑你的答案。我不想因为你的回答而夺走你的声望。 - Ron Tuffin
或将2更改为另一个数字,具体取决于嵌套的深度。 - clankill3r

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
@benj Utils只是一个通用类,您可以对其进行控制。您可以将该方法放在任何类中(请注意该方法是静态的)。 - Sydwell
1
好的,我只是想确认一下。感谢您提供这段漂亮的代码。 - Benj

1

在编写代码时,特别是在发布时进行编译,无法保证行号的一致性。我不建议使用行号来实现这个目的,最好的方法是提供异常抛出的位置信息(最简单的方法是将消息设置为包含方法调用详细信息的内容)。

您可能想要查看异常增强作为一种改进异常处理的技术 http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html


0

这是打印行号的代码。

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

创建一个全局公共静态方法,使打印日志更加容易。
  public static void Loge(Context context, String strMessage, int strLineNumber) {
    
        Log.e(context.getClass().getSimpleName(), strLineNumber + " : " + strMessage);
  
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接