Javaでログに行番号を出力するにはどうすればよいですか


132

行番号をログに出力する方法。いくつかの情報をログに出力するときに、その出力がソースコード内にある行番号も出力したいとします。スタックトレースで確認できるように、例外が発生した行番号が表示されます。スタックトレースは、例外オブジェクトで使用できます。

他の代替手段は、ログに出力するときに手動で行番号を含めるようなものです。他に方法はありますか?


4
短くて甘いワンライナーについては、@ Juanの過小評価された回答を参照してください!私は15ポイントをあきらめ、他のすべての回答に反対票を投じた:vとファンの賛成票を投じた
ネクロマンサー

回答:


102

Angsuman Chakrabortyから:

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

5
これにより、呼び出されたメソッドのreturnステートメントの行番号が常に返されます。必ずしもメソッド呼び出しの行番号ではありません。
Ron Tuffin 2008

[2]はgetLineNumber()の上にフレームを取得しませんか?(おそらく[1]はgetLineNumber()で、[0]はgetStackTrace()です)
Simon Buchan

1
私は少し遊んで、メソッド本体としてblah.getStackTrace [3] .getLineNumber()を使用すると、メソッドが呼び出された場所の行番号が返されます。
Ron Tuffin 2008

12
インデックスは、JVMバージョンに基づいて変更されます。1.4から1.5に変わったと思います。
エドトーマス

2
@SimonBuchanさん、名前には名前があります:)私はその記事をずっと前に書きました。
Angsuman Chakraborty

74

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

1
こんにちはマイケル、あなたの解決策に感謝します。ログ情報の行番号を表示することは私にとってうまくいきます...もう一度ありがとう。私はあなたのアンドロイドでの素晴らしい解決策を楽しみにしています。
サティッシュ

3
このコードを使用する前に、もう少し調査を行います。コードを投稿したところ、getStackTrace()[3]が機能しました。AndroidまたはJVMのバージョン、またはその他の要因に依存している可能性があります。
Michael Baltaks 2013年

3
この回答は機能しません。他のクラスからの呼び出し元の行番号ではなく、DebugLogクラスの行番号とクラス名と関数名が表示されます
Rahul

@Rahul getStackTrace()[3]ではなくgetStackTrace()[2]
user5480949

@ user5480949:JVMに関係なく、 "new Throwable()。getStackTrace()"を使用して、呼び出し関数の一貫したインデックスを取得します。(Thread.currentThread()。getStackTrace()の代わり)
Luc Bloom

36

迅速かつ汚い方法:

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

1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);私が必要とするすべての詳細を私に与えます:)
ネクロマンサー'29

JVMがこれが正しいスタックトレースを提供することは保証されていないことに注意してください。Hotspotがそのことを保証しているとは思いません(ただし、そのスタックトレースは通常は正しいです)。
–ThorbjørnRavn Andersen 2014

非常にクリーンな、クラスStackTraceElement l = new Exception()。getStackTrace()[1]; 私と一緒に仕事をする
vuhung3990 2015

@ThorbjørnRavnAndersen:JVMに関係なく、 "new Throwable()。getStackTrace()"を使用して、呼び出し関数の一貫したインデックスを取得します。(Thread.currentThread()。getStackTrace()の代わり)
Luc Bloom

昔の@LucBloomでは、スタックトレースが正確であることが保証されていませんでした。
するThorbjörnRavnアンデルセン

25

私はあなたの質問に答えないことで答えざるを得ません。デバッグをサポートするためだけに行番号を探していると思います。より良い方法があります。現在の行を取得するハックな方法があります。私が見たすべてが遅いです。java.util.loggingパッケージまたはlog4jのようなロギングフレームワークを使用する方がよいでしょう。これらのパッケージを使用すると、クラス名までのコンテキストを含めるようにログ情報を構成できます。その場合、各ログメッセージは、どこから来たかを知るのに十分なほど一意になります。その結果、コードには「ロガー」変数があり、この変数を介して呼び出します

logger.debug("a really descriptive message")

の代わりに

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


15

Log4Jでは、出力パターンの一部として行番号を含めることができます。参照http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.htmlを(変換パターンの重要な要素は、「L」である)これを行う方法の詳細については。ただし、Javadocには以下が含まれています。

警告発信者の位置情報の生成は非常に遅くなります。実行速度が問題にならない限り、使用しないでください。


基礎となるメカニズムは、JVMの最近のバージョンではるかに高速になりましたが、まだ慎重に使用する必要があります。
–ThorbjørnRavn Andersen 2014

7

@ simon.buchanによって投稿されたコードは動作します...

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

ただし、メソッド内で呼び出すと、常にメソッド内の行の行番号が返されるため、コードスニペットをインラインで使用します。


「2」はgetLineNumber()の呼び出し元の行番号を取得するためのものだと思いました。
Simon Buchan

@ simon.buchan-(私の最後のコメントに従って)回答を編集します。私はあなたの担当者をあなたの答えのために盗みたくありません。
Ron Tuffin 2008

または、2を別の番号に変更します。ネストの深さによって異なります。
clankill3r 2017

7

log4jなどのロギングツールキットを使用することをお勧めします。ロギングは実行時にプロパティファイルを介して設定可能であり、行番号/ファイル名のロギングなどの機能をオン/オフにすることができます。

PatternLayoutのjavadocを見ると、オプションの完全なリストが表示されます-あとは%Lです。


7

呼び出したメソッドのトレースと行番号を出力するこの小さなメソッドを使用します。

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

1
これはUtilどこから来たのですか?
2016年

@benj Utilsは、ユーザーが制御できる単なる一般的なクラスです。メソッドは任意のクラスに配置できます(メソッドは静的であることに注意してください)。
Sydwell 2016年

1
確かに、私は確認したかっただけです。この素敵なコードをありがとう。
ベンジ2016年

1

コードがリリース用にコンパイルされている場合は特に、コードとの行番号の一貫性を保証できません。とにかく、そのために行番号を使用することはお勧めしません。例外が発生した場所のペイロードを指定することをお勧めします(メソッド呼び出しの詳細を含むようにメッセージを設定するのは簡単な方法です)。

例外処理を改善するための手法として、例外の強化を検討することをお 勧めしますhttp://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html


0

リリース用にコンパイルされている場合、これは不可能です。Log4Jのようなものを調べて、ログに記録されたコードがどこで発生したかを厳密に特定するのに十分な情報を自動的に提供することもできます。


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

このリンクを見てください。その方法では、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
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

これらはすべて、現在のスレッドとメソッドの行番号を取得します。これは、例外が予想される場所で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

以下のコードは、ロギングメソッドが呼び出されたところから、クラス名とメソッド名をロギングしない行のテスト済みコードです。

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

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

これはまさにこのlib XDDLibに実装した機能 です。(しかし、それはアンドロイド用です)

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

ここに画像の説明を入力してください

上のワンクリックで下線付きのテキストログコマンドがある場所に移動します

これStackTraceElementは、このライブラリ外の最初の要素によって決定されます。したがって、このlibの外のどこかには、法的になりますlambda expressionstatic initialization blockなど、


-1

私のやり方

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.