Getting different results for getStackTrace()[2].getMethodName()

For logging purposes, I created a method logTitle() that prints out the calling method name for our TestNG tests. Sample code is below.

@Test
public void test1() throws Exception {
    method1();
}

public static void method1() throws Exception {
    Utils.logTitle(2);
}

...

public static void logTitle(Integer level) throws Exception {

    // Gets calling method name
    String method = Thread.currentThread().getStackTrace()[2].getMethodName();
    // This would get current method name
    switch (level) {
    case 1:
        logger.info("=======================================================");
        logger.info(method);
        logger.info("=======================================================");
        break;
    case 2:
        logger.info("------------------------------------");
        logger.info(method);
        logger.info("------------------------------------");
        break;
    case 3:
        logger.info("---------------------");
        logger.info(method);
        logger.info("---------------------");
        break;
    case 4:
        logger.info("--------- " + method + " ------------");
        break;
    default:
        logger.info(method);
    }
}

The problem is I am getting different results for logTitle() on two different machines.

Everyone's laptop returns correctly:

2016-06-20 14:22:06 INFO  - ------------------------------------
2016-06-20 14:22:06 INFO  - method1
2016-06-20 14:22:06 INFO  - ------------------------------------

Our dev unix box returns differently:

2016-06-20 14:42:26 INFO  - ------------------------------------
2016-06-20 14:42:26 INFO  - logTitle
2016-06-20 14:42:26 INFO  - ------------------------------------

This works correctly on everyone else's laptop, just not the dev unix box. I think the dev unix box is using IBM's version of Java, while everyone else is using Oracle's version of Java, but not sure if that is the culprit or not.

Any ideas?


I think its the specific depth that is causing the issue which is 2 in your scenario.

So, instead of writing

String method = Thread.currentThread().getStackTrace()[2].getMethodName();

if you write

StackTraceElement[] ste = Thread.currentThread().getStackTrace();
String method = null;
boolean doNext = false;
for (StackTraceElement s : ste) {
       if (doNext) {
          method = s.getMethodName();
          return;
       }
       doNext = s.getMethodName().equals("getStackTrace");
   }

It will work only for JDK 1.5+

The other option is as below:

String method = new Object(){}.getClass().getEnclosingMethod().getName();

Or a slower option will be :

String method = new Exception().getStackTrace()[0].getMethodName();

As this will create an instance of Exception everytime.

Hope that helps you out.


The simpler way to have a test method name is by using a @BeforeMethod and injecting the Method . See TestNG's documentation, here.

Just store the name somewhere and use it in your log (why not in a @AfterMethod ?)


From Javadoc:

Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.

So, the only guaranteed way to do this is to use aspects, or collect stack trace with some other custom way. But you can combine this approach with fallback to some way of getting current method's name (for case when your logTitle method will be inlined). It can be found here, for example. Again, no guarantee, but better chance.

链接地址: http://www.djcxy.com/p/82416.html

上一篇: 外部课程访问包

下一篇: 为getStackTrace()获取不同的结果[2] .getMethodName()