2013-07-04 34 views
24

リフレクションや素晴らしいAPIを使って現在の行番号を動的に取得する方法はありますか?例外が発生したときと同じように、行番号は、このようなスタックトレースでプリントアウトします:今動的に現在の行番号を取得

at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348) 

は、印刷したり、次のコードのようにログインする方法はありますか?

log.error("Error in: " + this.getClass.getName() + "at line #"+ this.getClass.getActualLine()); 

私は単に行番号を印刷しないのはなぜですか?コードが特定のlog.error()メソッド呼び出しの前に削除または追加される可能性があるからです。

+2

PatterningLayoutのAPIはこれに便利ですか? – sadhu

+0

'新しいThrowable'を作成し、スタックトレース要素にアクセスすることができます。 http://stackoverflow.com/questions/115008/how-can-we-print-line-numbers-to-the-log-in-java –

+2

@アンドレアス:「Throwable」は必要ありません:[' Thread.getStackTrace() '](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#getStackTrace())で十分です。 –

答えて

7

IのにThread.currentThreadを(使用することができた)ようなので、最初のメソッドを呼び出したコードの行番号を生成するために一緒に働く機能のセットを作成するgetStackTraceメソッド()メソッド:

/** @return The line number of the code that ran this method 
* @author Brian_Entei */ 
public static int getLineNumber() { 
    return ___8drrd3148796d_Xaf(); 
} 

/** This methods name is ridiculous on purpose to prevent any other method 
* names in the stack trace from potentially matching this one. 
* 
* @return The line number of the code that called the method that called 
*   this method(Should only be called by getLineNumber()). 
* @author Brian_Entei */ 
private static int ___8drrd3148796d_Xaf() { 
    boolean thisOne = false; 
    int thisOneCountDown = 1; 
    StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 
    for(StackTraceElement element : elements) { 
     String methodName = element.getMethodName(); 
     int lineNum = element.getLineNumber(); 
     if(thisOne && (thisOneCountDown == 0)) { 
      return lineNum; 
     } else if(thisOne) { 
      thisOneCountDown--; 
     } 
     if(methodName.equals("___8drrd3148796d_Xaf")) { 
      thisOne = true; 
     } 
    } 
    return -1; 
} 

希望します。私はこれらをユーティリティクラスに入れて、途中ではなく、簡単にアクセスできるようにします。第2の方法は、第1の方法以外の方法が常に正しく動作するように呼び出さないようにするためにプライベートな方法です。

+0

良いこと、これは受け入れられた答えでなければなりません。 –

34

あなたはThrowableを作成し、そのStackTraceElements使用することができます。

System.err.println(new Throwable().getStackTrace()[0].getLineNumber()); 

@Joachimが言ったように、あなたもThread.getStackTrace()を使用することができ、例えばを以下のような

System.err.println(Thread.currentThread().getStackTrace()[1].getLineNumber()); 

は、第二のアプローチは多少異なる配列を返すことに注意してください - あなたはそれが最初のようgetStackTrace()への呼び出し自体が含まれているため、現在行番号を取得するには、インデックス1と配列要素を使用する必要があります素子。

また、@ Joachimの回答からのログとパフォーマンスに関するコメントにも注意してください。

+1

異なる結果が返されるいくつかのJVMで。少なくともAIXのIBM JVMでは、スタックにはスロー可能なコンストラクタが含まれていました。 getStackTraceのjavadocを参照してください。 '配列の長さが0でないと仮定して配列の0番目の要素は、スタックの最上部を表します。これは、シーケンス内の最後のメソッド呼び出しです。典型的には、これは、このスローブラブルが作成されスローされたポイントです。だからBrian_Enteiのソリューションはより弾力性があります。 –

15

まず、何かの場合、ロギングパターン(またはレイアウト、またはロギングフレームワークがその部分を呼び出すもの)はこれを行う必要があります。コード内のロガー呼び出しはのみ実際のビジネス情報を記述する必要があります。ロガーによってどこに追加されるべきかに関する情報。

次のように、Javaはこのために最適化されていないため、この種の操作を行うのは時間がかかります。実行時に、JVMはその状態を検査し、デバッグ情報をロード/解析し、与えられた命令に対応する行番号を見つける必要があります。そのため、この種の情報は通常例外が発生したときにのみ与えられます(その場合には、すでに問題が発生しており、にはが分かります)。

そして最後にではなく、少なくとも:あなたが自分でその情報を必要とするいくつかの理由で場合、あなたはThread.getStackTrace()を使用して、その上に第二StackTraceElementを検査することができます。

0

次のスニペットを使用して、の例外行番号を取得することもできます。あなたのutilクラスでは、以下のutilメソッドを使用してください。catchブロックから

public static int getExceptionLineNumber(Exception e, String methodNameExp) 
{ 
    StackTraceElement ele = Arrays.stream(e.getStackTrace()).filter(o -> o.getMethodName().equals(methodNameExp)).findAny().orElse(null); 
    if(ele != null){ 
     return ele.getLineNumber(); 
    } 
    return -1; 
} 

あなたは以下のように呼び出すことができます。

catch (Exception e){ 
     logger.info("Exception line number "+ Util.getExceptionLineNumber(e, new Object(){}.getClass().getEnclosingMethod().getName())); 
    } 

は、この作品を願って! :)

関連する問題