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


132

如何将行号打印到日志中。说在将某些信息输出到日志时,我还想在源代码中输出该行的行号。正如我们在堆栈跟踪中所看到的,它显示发生异常的行号。堆栈跟踪可用于异常对象。

其他选择可能类似于在打印到日志时手动包括行号。还有其他办法吗?


4
请参阅下面的@Juan未被充分理解的答案,以获取简短而甜美的一句!我只是放弃了15分,表示反对所有其他答案:v和反对Juan's
necromancer

Answers:


102

来自Angsuman Chakraborty

/** 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。
Ed Thomas

2
嘿@SimonBuchan,这个家伙叫一个名字:)我早就写了那篇文章。
Angsuman Chakraborty

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的版本或其他一些因素。
Michael Baltaks 2013年

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]);给了我我需要的所有详细信息:)
necromancer 2014年

请注意,不保证JVM在正确的地方提供堆栈跟踪。我不相信Hotspot可以做到这一点(但通常它的stacktrace是正确的)。
托尔比约恩Ravn的安徒生

非常干净,类StackTraceElement l = new Exception()。getStackTrace()[1]; 和我
一起

@ThorbjørnRavnAndersen:使用“ new Throwable()。getStackTrace()”来为您的调用函数获取一致的索引,而与JVM无关。(代替Thread.currentThread()。getStackTrace())
卢克·布鲁姆

在过去,@ LucBloom不能保证堆栈跟踪是准确的。
托尔比约恩Ravn的安徒生

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的最新版本中,其基本机制已经变得更快,但仍应谨慎使用。
托尔比约恩Ravn的安徒生

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只是您可以控制的常规类。您可以将方法放在任何类中(请注意该方法是静态的)。
Sydwell '16

1
好的,我只是想确定一下。感谢您提供的这段精美代码。
杰2016年


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

然后使用特定的实用程序方法获取正确的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;
  }


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

所有这些都为您提供了当前线程和方法的行号,如果您在希望发生异常的地方使用try catch,那么它们的工作效果很好。但是,如果要捕获任何未处理的异常,则使用的是默认的未捕获异常处理程序,当前线程将返回处理程序函数的行号,而不是引发异常的类方法。不用使用Thread.currentThread(),只需使用异常处理程序传递的Throwable即可:

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

在上面的代码中,在处理函数(fShowUncaughtMessage)中使用e.getStackTrace()[0]获取违规者。


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))

在此处输入图片说明

单击带下划线的文本以导航到log命令所在的位置

StackTraceElement由该库外的第一个元素确定。因此,这种LIB以外的任何地方将是合法的,包括lambda expressionstatic 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;
  }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.