【Java】スタック情報の取得 ~StackTraceElement~

はじめに

 * log4jの機能ではないが、スタック情報をログにはくことで、
   デバッグに役立つので、カテゴリー(書庫)を「Javaログ関連/log4j」にしておく。

構文

StackTraceElement[] stackTraces =
		Thread.currentThread().getStackTrace();

サンプル

package com;

public class Sample {
   public static void main(String[] args) {
      StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();

      for (StackTraceElement stackTraceElement : stackTraces) {
         String className = stackTraceElement.getClassName();
         String methodName = stackTraceElement.getMethodName();
         int lineNumber = stackTraceElement.getLineNumber();

         String content = String.format("%s %s() [%d]", className, methodName, lineNumber);
         System.out.println("---------");
         System.out.println(content);
         System.out.println("---------");
      }
   }
}

出力

---------
java.lang.Thread getStackTrace() [-1]
---------
---------
com.Sample main() [5]
---------

ログに応用する

サンプル1

* 対象のStackTraceElementが固定(今回の場合「Index = 3」)でわかっている場合

Logger.java

package com.log;

public class Logger {
   private static int Index = 3;
   
   public static void WriteLog(String content) {
      StackTraceElement stackTraceElement = 
            Logger.getStackTraceElement(Logger.Index);
      
      String className = stackTraceElement.getClassName();
      String methodName = stackTraceElement.getMethodName();
      int lineNumber = stackTraceElement.getLineNumber();
      
      String logContent = 
            String.format("%s.%s() [%d] : %s",
                  className, methodName, lineNumber, content);
      System.out.println(logContent);
   }
   
   private static StackTraceElement getStackTraceElement(int index) {
      StackTraceElement[] stackTraces =
            Thread.currentThread().getStackTrace();
      return stackTraces[index];
   }
}

Sample.java

package com;

import com.log.Logger;

public class Sample {
   public static void main(String[] args) {
      Logger.WriteLog("1st");
      Sample.methodA();
   }
   
   private static void methodA() {
      Logger.WriteLog("2nd");
      Sample.methodB();
   }
   
   private static void methodB() {
      Logger.WriteLog("3rd");
   }
}

出力

com.Sample.main() [7] : 1st
com.Sample.methodA() [12] : 2nd
com.Sample.methodB() [17] : 3rd

サンプル2

* 汎用的に使える方法
* 「Sample.java」はサンプル1を使う

Util.java

* Class.forName(【Class名】) は、文字列からインスタンスを生成
public class Util {
   
   public static StackTraceElement getStackTraceElement(
         Class<?> ignoredClass) {
      StackTraceElement[] stackTraceElements =
            Thread.currentThread().getStackTrace();
      
      boolean isFoundUtilClass = false;
      Class<?> targetClass;
      for (StackTraceElement stackTraceElement : stackTraceElements) {
         try {
            targetClass = Class.forName(stackTraceElement.getClassName());
         } catch (ClassNotFoundException e) {
            e.printStackTrace();
            continue;
         }

         if (targetClass.equals(Util.class)) {
            isFoundUtilClass = true;
            continue;
         }
         if (!isFoundUtilClass ||
               Util.isImplemented(ignoredClass, targetClass)) {
            continue;
         }
         
         return stackTraceElement;
      }
      return null;
   }
   
   public static boolean isImplemented(
         Class<?> interfaceClass, Class<?> targetClass) {
      
      if (interfaceClass.equals(targetClass) ||
            interfaceClass.isInterface() && interfaceClass.isAssignableFrom(targetClass)) {
         return true;
      }
      return false;
   }
}

ILogger.java

package com.log;

public interface ILogger {
}

Logger.java

package com.log;

public class Logger implements ILogger {
   public static void WriteLog(String content) {
      StackTraceElement stackTraceElement = 
            Util.getStackTraceElement(ILogger.class);
      
      String className = stackTraceElement.getClassName();
      String methodName = stackTraceElement.getMethodName();
      int lineNumber = stackTraceElement.getLineNumber();
      
      String logContent = 
            String.format("%s.%s() [%d] : %s",
                  className, methodName, lineNumber, content);
      System.out.println(logContent);
   }
}