Bagaimana kita bisa mencetak nomor baris ke log di java

132

Cara mencetak nomor baris ke log. Katakanlah ketika mengeluarkan beberapa informasi ke log, saya juga ingin mencetak nomor baris di mana keluaran itu dalam kode sumber. Seperti yang dapat kita lihat di tumpukan jejak, ini menampilkan nomor baris di mana pengecualian telah terjadi. Jejak tumpukan tersedia pada objek pengecualian.

Alternatif lain bisa seperti secara manual termasuk nomor baris saat mencetak ke log. Apakah ada cara lain?

Bobby Kumar
sumber
4
lihat @ Juan jawaban yang kurang dihargai di bawah ini untuk kalimat singkat dan manis! Saya baru saja memberikan 15 poin rep downvoting semua jawaban lain: v dan upvoting Juan
necromancer

Jawaban:

102

Dari Angsuman Chakraborty :

/** Get the current line number.
 * @return int - Current line number.
 */
public static int getLineNumber() {
    return Thread.currentThread().getStackTrace()[2].getLineNumber();
}
Simon Buchan
sumber
5
Ini akan selalu mengembalikan nomor baris dari pernyataan kembali dalam metode yang dipanggil dan tidak harus nomor baris dari panggilan metode.
Ron Tuffin
Bukankah [2] mendapatkan bingkai di atas getLineNumber ()? ([1] menjadi getLineNumber (), dan [0] menjadi getStackTrace (), mungkin)
Simon Buchan
1
Saya bermain-main sedikit dan jika Anda menggunakan blah.getStackTrace [3] .getLineNumber () sebagai tubuh metode ia mengembalikan nomor baris di mana metode itu dipanggil.
Ron Tuffin
12
Indeks akan berubah berdasarkan versi JVM. Saya percaya itu berubah dari 1,4 menjadi 1,5.
Ed Thomas
2
Hey @SimonBuchan, Pria itu punya nama :) Saya menulis artikel itu sejak dulu.
Angsuman Chakraborty
74

Kami akhirnya menggunakan kelas khusus seperti ini untuk pekerjaan Android kami:

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);
  }
 }
}
Michael Baltaks
sumber
1
Halo Michael, terima kasih atas solusinya, berfungsi baik bagi saya untuk menampilkan nomor baris untuk info log .... terima kasih lagi. Saya menantikan solusi hebat Anda di android.
sathish
3
Saya akan melakukan penelitian lebih lanjut tentang kode ini sebelum menggunakannya - ketika saya memposting kode, getStackTrace () [3] berhasil. Mungkin tergantung pada versi Android atau JVM, atau faktor lain.
Michael Baltaks
3
jawaban ini tidak berfungsi, ini menunjukkan no baris dan nama kelas dan nama fungsi kelas DebugLog bukan no baris penelepon dari kelas lain
Rahul
@Rahul itu seharusnya getStackTrace()[3]bukangetStackTrace()[2]
user5480949
@ user5480949: Gunakan "new Throwable (). getStackTrace ()" untuk mendapatkan indeks yang konsisten untuk fungsi panggilan Anda, terlepas dari JVM. (Alih-alih Thread.currentThread (). GetStackTrace ())
Luc Bloom
36

Cara cepat dan kotor:

System.out.println("I'm in line #" + 
    new Exception().getStackTrace()[0].getLineNumber());

Dengan beberapa perincian lebih lanjut:

StackTraceElement l = new Exception().getStackTrace()[0];
System.out.println(
    l.getClassName()+"/"+l.getMethodName()+":"+l.getLineNumber());

Itu akan menampilkan sesuatu seperti ini:

com.example.mytest.MyClass/myMethod:103
Juan
sumber
1
System.out.println("i am here: " + new Exception().getStackTrace()[0]);memberi saya semua detail yang saya butuhkan :)
necromancer
Perhatikan bahwa JVM tidak dijamin untuk memberikan stacktrace di mana ini benar. Saya tidak percaya Hotspot membuat jaminan itu baik (tapi stacktraces-nya biasanya benar).
Thorbjørn Ravn Andersen
sangat bersih, kelas StackTraceElement l = Pengecualian baru (). getStackTrace () [1]; bekerja dengan saya
vuhung3990
@ ThorbjørnRavnAndersen: Gunakan "new Throwable (). GetStackTrace ()" untuk mendapatkan indeks yang konsisten untuk fungsi panggilan Anda, terlepas dari JVM. (Alih-alih Thread.currentThread (). GetStackTrace ())
Luc Bloom
@LucBloom di masa lalu Anda tidak dijamin bahwa jejak stack akurat.
Thorbjørn Ravn Andersen
25

Saya terpaksa menjawab dengan tidak menjawab pertanyaan Anda. Saya berasumsi bahwa Anda mencari nomor baris semata-mata untuk mendukung debugging. Ada cara yang lebih baik. Ada cara hack untuk mendapatkan baris saat ini. Semua yang saya lihat lambat. Anda lebih baik menggunakan kerangka kerja logging seperti itu di paket java.util.logging atau log4j . Menggunakan paket-paket ini Anda dapat mengkonfigurasi informasi logging Anda untuk memasukkan konteks ke nama kelas. Maka setiap pesan log akan cukup unik untuk mengetahui dari mana asalnya. Akibatnya, kode Anda akan memiliki variabel 'logger' yang Anda hubungi

logger.debug("a really descriptive message")

dari pada

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

James A Wilson
sumber
15

Log4J memungkinkan Anda untuk memasukkan nomor baris sebagai bagian dari pola outputnya. Lihat http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html untuk detail tentang cara melakukan ini (elemen kunci dalam pola konversi adalah "L"). Namun, Javadoc meliputi:

PERINGATAN Menghasilkan informasi lokasi pemanggil sangat lambat. Penggunaannya harus dihindari kecuali kecepatan eksekusi tidak menjadi masalah.

Jim Kiley
sumber
Mekanisme yang mendasari telah menjadi jauh lebih cepat di versi JVM yang lebih baru, tetapi masih harus digunakan hemat.
Thorbjørn Ravn Andersen
7

Kode yang diposting oleh @ simon.buchan akan berfungsi ...

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

Tetapi jika Anda memanggilnya dalam suatu metode, ia akan selalu mengembalikan nomor baris dari garis dalam metode, jadi alih-alih gunakan potongan inline kode.

Ron Tuffin
sumber
Saya kira '2' adalah untuk mendapatkan nomor baris pemanggil getLineNumber ().
Simon Buchan
@ simon.buchan - edit jawaban Anda (sesuai komentar terakhir saya). Saya tidak ingin mencuri perwakilan Anda untuk jawaban Anda.
Ron Tuffin
Atau ubah 2 ke nomor lain. Tergantung seberapa dalam sarangnya.
clankill3r
7

Saya akan merekomendasikan menggunakan toolkit logging seperti log4j . Logging dapat dikonfigurasi melalui file properti saat runtime, dan Anda dapat menghidupkan / mematikan fitur seperti nomor baris / nama file logging.

Melihat javadoc untuk PatternLayout memberi Anda daftar lengkap opsi - yang Anda cari adalah% L.


sumber
7

Saya menggunakan metode kecil ini yang menampilkan jejak dan nomor baris dari metode yang memanggilnya.

 Log.d(TAG, "Where did i put this debug code again?   " + Utils.lineOut());

Klik dua kali output untuk pergi ke baris kode sumber!

Anda mungkin perlu menyesuaikan nilai level tergantung di mana Anda meletakkan kode Anda.

public static String lineOut() {
    int level = 3;
    StackTraceElement[] traces;
    traces = Thread.currentThread().getStackTrace();
    return (" at "  + traces[level] + " " );
}
Sydwell
sumber
1
Dari mana ini Utilberasal?
Benj
@benj Utils hanyalah kelas umum yang dapat Anda kendalikan. Anda bisa meletakkan metode ini di kelas mana saja (perhatikan metode ini statis).
Sydwell
1
OK, saya hanya ingin memastikan. Terima kasih atas sedikit kode yang bagus ini.
Benj
1

Anda tidak dapat menjamin konsistensi nomor baris dengan kode, terutama jika dikompilasi untuk rilis. Saya tidak akan merekomendasikan menggunakan nomor baris untuk tujuan itu, akan lebih baik untuk memberikan payload tempat di mana pengecualian dimunculkan (metode sepele adalah mengatur pesan untuk memasukkan rincian dari pemanggilan metode).

Anda mungkin ingin melihat pengayaan pengecualian sebagai teknik untuk meningkatkan penanganan pengecualian http://tutorials.jenkov.com/java-exception-handling/exception-enrichment.html

UberAlex
sumber
0

Jika sudah dikompilasi untuk rilis ini tidak mungkin. Anda mungkin ingin melihat sesuatu seperti Log4J yang secara otomatis akan memberi Anda informasi yang cukup untuk menentukan dengan cermat di mana kode yang dicatat.

GBa
sumber
0

pertama metode umum (dalam kelas utilitas, dalam kode java1.4 tua biasa, Anda mungkin harus menulis ulang untuk java1.5 dan lebih banyak lagi)

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

Kemudian metode utilitas khusus untuk mendapatkan stackElement yang tepat:

/**
   * 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;
  }
VONC
sumber
0

Lihatlah tautan ini . Dalam metode itu Anda dapat melompat ke kode baris Anda, ketika Anda mengklik dua kali pada baris LogCat.

Anda juga dapat menggunakan kode ini untuk mendapatkan nomor baris:

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;
}
Bobs
sumber
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();
}
Raymond
sumber
0

Ini semua memberi Anda nomor baris utas dan metode Anda saat ini yang bekerja sangat baik jika Anda menggunakan try catch di mana Anda mengharapkan pengecualian. Tetapi jika Anda ingin menangkap pengecualian tidak tertangani maka Anda menggunakan penangan pengecualian tidak tertangkap default dan utas saat ini akan mengembalikan nomor baris dari fungsi penangan, bukan metode kelas yang melempar pengecualian. Alih-alih menggunakan Thread.currentThread () cukup gunakan Throwable yang diteruskan oleh handler pengecualian:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable e) {              
                if(fShowUncaughtMessage(e,t))               
                    System.exit(1);
            }
        });

Dalam penggunaan di atas, gunakan e.getStackTrace () [0] pada fungsi handler Anda (fShowUncaughtMessage) untuk mendapatkan pelaku.

Menandai
sumber
0

Kode di bawah ini adalah kode yang diuji untuk jalur logging, tanpa nama kelas dan nama metode dari mana metode logging dipanggil

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;
}
}
Rahul
sumber
0

The stackLeveltergantung pada kedalaman Anda memanggil metode ini. Anda dapat mencoba dari 0 hingga banyak untuk melihat perbedaannya.

Jika stackLevellegal, Anda akan mendapatkan string sepertijava.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);
}
Loyea
sumber
0

Ini persis fitur yang saya terapkan dalam lib XDDLib ini . (Tapi, ini untuk android)

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

masukkan deskripsi gambar di sini

Satu klik pada teks yang digarisbawahi untuk menavigasi ke tempat perintah log

Itu StackTraceElementditentukan oleh elemen pertama di luar perpustakaan ini. Dengan demikian, di manapun di luar lib ini akan menjadi hukum, termasuk lambda expression, static initialization block, dll

Owen Chen
sumber
-1

Cara saya bekerja untuk saya

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;
  }
EmiDemi
sumber
-1

Anda dapat menggunakan -> Reporter.log ("");

rutvij gusani
sumber