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

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

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

0

这正是我在XDDLib中实现的功能。(但是,它是为Android设计的)

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

enter image description here

点击下划线文本即可导航到日志命令所在位置

StackTraceElement由此库之外的第一个元素确定。因此,任何此库之外的地方都是合法的,包括lambda表达式静态初始化块等。


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
如果已经编译发布,这是不可能的。您可能需要查看类似于Log4J的东西,它将自动为您提供足够的信息,以便相当准确地确定记录代码发生的位置。

0

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

首先是通用方法(在实用类中,使用普通的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
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

看看这个链接。在那个方法中,当你双击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

这些都可以获取当前线程和方法的行号,如果您在使用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

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

这意味着如果从上面的 3 个嵌套方法中执行 Thread.currentThread().getStackTrace()[X].getLineNumber(); 行,则索引号必须为 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正式教育的人,这让我对编译器的工作方式有了全新的认识。

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