【问题标题】:How can we print line numbers to the log in java我们如何在java中将行号打印到日志中
【发布时间】:2008-09-22 14:02:08
【问题描述】:

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

其他替代方法可能是在打印到日志时手动包含行号。有没有其他办法?

【问题讨论】:

  • 请参阅下面@Juan 未被充分理解的答案,以获得简短而甜蜜的单线!我只是放弃了 15 分代表对所有其他答案投了反对票:v 并赞成胡安的

标签: java logging


【解决方案1】:

来自Angsuman Chakraborty(存档):

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

【讨论】:

  • 这将始终返回被调用方法中return语句的行号,不一定是方法调用的行号。
  • 我玩了一下,如果你使用 blah.getStackTrace[3].getLineNumber() 作为方法体,它会返回调用方法的行号。
  • 索引会根据JVM版本变化。我相信它从 1.4 变成了 1.5。
  • 嘿@SimonBuchan,这家伙有个名字:) 我很久以前写过那篇文章。
  • 这看起来很无辜,但我想知道getStackTrace() 的成本是多少。看起来手头很重。我希望有一个编译器解决方案/宏,可以在编译时对数字进行硬编码,就像 c++ 一样。仍然 - 这是最好的可用答案。
【解决方案2】:

我们最终为我们的 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);
  }
 }
}

【讨论】:

  • 嗨迈克尔,感谢您的解决方案,我可以很好地显示日志信息的行号....再次感谢。我期待您在 android 中提供出色的解决方案。
  • 在使用此代码之前,我会对其进行更多研究 - 当我发布代码时,getStackTrace()[3] 有效。它可能取决于 Android 或 JVM 的版本,或其他一些因素。
  • 这个答案不起作用它显示DebugLog类的行号和类名和函数名而不是来自其他类的调用者的行号
  • @Rahul 应该是 getStackTrace()[3] 而不是 getStackTrace()[2]
  • @user5480949:使用“new Throwable().getStackTrace()”为调用函数获取一致的索引,无论 JVM 是什么。 (而不是 Thread.currentThread().getStackTrace())
【解决方案3】:

快速而肮脏的方式:

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

【讨论】:

  • System.out.println("i am here: " + new Exception().getStackTrace()[0]); 提供了我需要的所有详细信息 :)
  • 请注意,JVM 不能保证在正确的地方给出堆栈跟踪。我也不相信 Hotspot 会做出这样的保证(但它的堆栈跟踪通常是正确的)。
  • 非常干净,类 StackTraceElement l = new Exception().getStackTrace()[1];和我一起工作
  • @ThorbjørnRavnAndersen:使用“new Throwable().getStackTrace()”为您的调用函数获取一致的索引,而不管 JVM。 (而不是 Thread.currentThread().getStackTrace())
  • @LucBloom 在过去,您无法保证堆栈跟踪是准确的。
【解决方案4】:

我不得不回答你的问题。我假设您正在寻找仅支持调试的行号。有更好的方法。有一些骇人听闻的方法可以获取当前行。我所看到的都是缓慢的。您最好使用 java.util.logging 包或log4j 中的日志框架。使用这些包,您可以配置日志记录信息以将上下文包括到类名。然后每条日志消息将是独一无二的,足以知道它来自哪里。因此,您的代码将有一个您通过调用的“记录器”变量

logger.debug("a really descriptive message")

而不是

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

【讨论】:

    【解决方案5】:

    Log4J 允许您将行号作为其输出模式的一部分。有关如何执行此操作的详细信息,请参阅http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html(转换模式中的关键元素是“L”)。但是,Javadoc 确实包含以下内容:

    警告生成呼叫者位置 信息极其缓慢。它是 除非执行,否则应避免使用 速度不是问题。

    【讨论】:

    • 在较新版本的 JVM 中,底层机制变得更快,但仍应谨慎使用。
    【解决方案6】:

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

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

    但是如果你在一个方法中调用它,它总是会返回方法中行的行号,所以宁愿使用代码 sn-p inline。

    【讨论】:

    • 我猜 '2' 是为了获取 getLineNumber() 调用者的行号。
    • @simon.buchan - 编辑您的答案(根据我的最后评论)。我不想为了你的答案而窃取你的代表。
    • 或者把2换成别的数字。取决于嵌套的深度。
    【解决方案7】:

    我建议使用 log4j 之类的日志记录工具包。日志可在运行时通过属性文件进行配置,您可以打开/关闭行号/文件名日志等功能。

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

    【讨论】:

      【解决方案8】:

      我使用这个小方法输出调用它的方法的跟踪和行号。

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

      【讨论】:

      • 这个Util来自哪里?
      • @benj Utils 只是您可以控制的通用类。您可以将该方法放在任何类中(注意该方法是静态的)。
      • 好的,我只是想确定一下。感谢您提供这么好的代码。
      【解决方案9】:

      您无法保证行号与代码的一致性,尤其是在为发布而编译的情况下。无论如何,我不建议为此使用行号,最好提供引发异常的位置的有效负载(简单的方法是将消息设置为包含方法调用的详细信息)。

      您可能希望将异常丰富视为一种改进异常处理的技术 http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html

      【讨论】:

        【解决方案10】:

        如果它是为发布而编译的,这是不可能的。您可能想研究一下 Log4J 之类的东西,它会自动为您提供足够的信息来非常接近地确定记录的代码发生的位置。

        【讨论】:

          【解决方案11】:

          首先是通用方法(在实用程序类中,不过在普通的旧 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;
            }
          

          【讨论】:

            【解决方案12】:

            这是我们使用的记录器。

            它封装了 Android Logger 并显示类名、方法名和行号。

            http://www.hautelooktech.com/2011/08/15/android-logging/

            【讨论】:

              【解决方案13】:

              看看this link。在该方法中,当您双击 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;
              }
              

              【讨论】:

                【解决方案14】:
                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();
                }
                

                【讨论】:

                  【解决方案15】:

                  这些都可以为您提供当前线程和方法的行号,如果您在预期异常的地方使用 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] 来获取违规者。

                  【讨论】:

                    【解决方案16】:

                    下面的代码是记录行的测试代码,没有类名和调用记录方法的方法名

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

                    【讨论】:

                      【解决方案17】:

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

                      【讨论】:

                        【解决方案18】:

                        这正是我在这个库中实现的功能 XDDLib。 (但是,它适用于安卓)

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

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

                        StackTraceElement 由该库外的第一个元素确定。因此,此库之外的任何地方都是合法的,包括lambda expressionstatic initialization block 等。

                        【讨论】:

                          【解决方案19】:

                          对于任何想知道的人,getStackTrace()[3] 方法中的索引表示触发行在实际 .getStackTrace() 方法(不包括执行行)之前经过的线程数量。

                          这意味着如果Thread.currentThread().getStackTrace()[X].getLineNumber(); 行从上面的3个嵌套方法执行,则索引号必须为3

                          例子:

                          第一层

                          private static String message(String TAG, String msg) {
                          
                              int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();
                          
                              return ".(" + TAG + ".java:"+ lineNumber +")" + " " + msg;
                          }
                          

                          第二层

                          private static void print(String s) {
                                  System.out.println(s);
                          }
                          

                          第三层

                          public static void normal(
                                  String TAG,
                                  String message
                          ) {
                              print(
                                      message(
                                              TAG,
                                              message
                                      )
                              );
                          }
                          

                          执行行:

                              Print.normal(TAG, "StatelessDispatcher");
                          

                          作为一个没有接受过任何正式 IT 教育的人,这对编译器的工作原理很开放。

                          【讨论】:

                            【解决方案20】:

                            我的方式适合我

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

                            【讨论】:

                              【解决方案21】:

                              你可以使用 -> Reporter.log("");

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 2021-08-16
                                • 2015-05-05
                                • 2022-01-22
                                • 2017-11-16
                                • 1970-01-01
                                • 1970-01-01
                                • 2017-06-27
                                相关资源
                                最近更新 更多