เราจะพิมพ์หมายเลขบรรทัดไปยัง log in java ได้อย่างไร


133

วิธีพิมพ์หมายเลขบรรทัดลงในบันทึก สมมติว่าเมื่อส่งข้อมูลบางอย่างไปยังบันทึกฉันต้องการพิมพ์หมายเลขบรรทัดโดยที่เอาต์พุตนั้นอยู่ในซอร์สโค้ดด้วย ดังที่เราเห็นในการติดตามสแต็กจะแสดงหมายเลขบรรทัดที่มีข้อยกเว้นเกิดขึ้น การติดตามสแต็กมีอยู่ในอ็อบเจ็กต์ข้อยกเว้น

ทางเลือกอื่น ๆ เช่นการใส่หมายเลขบรรทัดด้วยตนเองเมื่อพิมพ์ลงในบันทึก มีวิธีอื่น ๆ ?


4
ดูคำตอบที่ไม่ได้รับการยอมรับของ @ Juan ด้านล่างสำหรับซับในสั้นและหวาน! ฉันเพิ่งยอมแพ้ตัวแทน 15 คะแนนในการลงคะแนนคำตอบอื่น ๆ ทั้งหมด: v และการโหวตของ Juan
เนโครแมนเซอร์

คำตอบ:


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 ใน method ที่เรียกเสมอและไม่จำเป็นต้องเป็นหมายเลขบรรทัดของการเรียก method
Ron Tuffin

[2] ไม่ได้รับกรอบด้านบน getLineNumber ()? ([1] เป็น getLineNumber () และ [0] เป็น getStackTrace () สันนิษฐานว่า)
Simon Buchan

1
ฉันเล่นไปสักพักและถ้าคุณใช้ blah.getStackTrace [3] .getLineNumber () เป็นตัวเมธอดมันจะส่งคืนหมายเลขบรรทัดของตำแหน่งที่เมธอดถูกเรียก
Ron Tuffin

12
ดัชนีจะเปลี่ยนไปตามเวอร์ชัน JVM ฉันเชื่อว่ามันเปลี่ยนจาก 1.4 เป็น 1.5
Ed Thomas

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
สวัสดี Michael ขอบคุณสำหรับวิธีการแก้ปัญหาของคุณการแสดงหมายเลขบรรทัดสำหรับข้อมูลบันทึกทำงานได้ดี .... ขอบคุณอีกครั้ง ฉันรอคอยสำหรับโซลูชันที่ยอดเยี่ยมของคุณใน Android
sathish

3
ฉันจะหาข้อมูลเพิ่มเติมเกี่ยวกับโค้ดนี้ก่อนที่จะใช้ - เมื่อฉันโพสต์รหัส getStackTrace () [3] ใช้งานได้ อาจขึ้นอยู่กับเวอร์ชันของ Android หรือ JVM หรือปัจจัยอื่น ๆ
Michael Baltaks

3
คำตอบนี้ใช้ไม่ได้ แต่จะแสดงหมายเลขบรรทัดและชื่อคลาสและชื่อฟังก์ชันของคลาส DebugLog ไม่ใช่ line no ของผู้โทรจากคลาสอื่น
Rahul

@Rahul มันควรจะgetStackTrace()[3]แทนgetStackTrace()[2]
user5480949

@ user5480949: ใช้ "new Throwable (). getStackTrace ()" เพื่อรับดัชนีที่สอดคล้องกันสำหรับฟังก์ชันการโทรของคุณโดยไม่คำนึงถึง JVM (แทน 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]);ให้รายละเอียดทั้งหมดที่ฉันต้องการ :)
necromancer

โปรดทราบว่า JVM ไม่รับประกันว่าจะให้ stacktrace ในที่ที่ถูกต้อง ฉันไม่เชื่อว่า Hotspot รับประกันอย่างใดอย่างหนึ่ง (แต่สแต็กเทรซปกติจะถูกต้อง)
Thorbjørn Ravn Andersen

สะอาดมากคลาส StackTraceElement l = new Exception (). getStackTrace () [1]; ทำงานกับฉัน
vuhung3990

@ ThorbjørnRavnAndersen: ใช้ "new Throwable (). getStackTrace ()" เพื่อรับดัชนีที่สอดคล้องกันสำหรับฟังก์ชันการโทรของคุณโดยไม่คำนึงถึง JVM (แทน Thread.currentThread (). getStackTrace ())
Luc Bloom

@LucBloom ในสมัยก่อนคุณไม่ได้รับการรับรองว่าการติดตามสแต็กถูกต้อง
Thorbjørn Ravn Andersen

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ørn Ravn Andersen

7

รหัสที่โพสต์โดย @ simon.buchan จะใช้งานได้ ...

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

แต่ถ้าคุณเรียกมันด้วยวิธีการมันจะส่งคืนหมายเลขบรรทัดของบรรทัดในวิธีการเสมอดังนั้นให้ใช้ข้อมูลโค้ดแบบอินไลน์


ฉันเดาว่า '2' คือการรับหมายเลขบรรทัดของผู้โทร getLineNumber ()
Simon Buchan

@ simon.buchan - แก้ไขคำตอบของคุณ (ตามความคิดเห็นล่าสุดของฉัน) ฉันไม่ต้องการขโมยตัวแทนของคุณสำหรับคำตอบของคุณ
รอนทัฟฟิน

หรือเปลี่ยน 2 เป็นตัวเลขอื่น ขึ้นอยู่กับว่ามันซ้อนกันลึกแค่ไหน
clankill3r

7

ฉันจะแนะนำให้ใช้ชุดเครื่องมือการเข้าสู่ระบบเช่นlog4j การบันทึกสามารถกำหนดค่าได้ผ่านไฟล์คุณสมบัติที่รันไทม์และคุณสามารถเปิด / ปิดคุณสมบัติต่างๆเช่นการบันทึกหมายเลขบรรทัด / ชื่อไฟล์

การดู javadoc สำหรับPatternLayoutจะให้รายการตัวเลือกทั้งหมดแก่คุณสิ่งที่คุณต้องการคือ% 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มาจากไหน?
เบญจ

@benj Utils เป็นเพียงคลาสทั่วไปที่คุณสามารถควบคุมได้ คุณสามารถใส่เมธอดในคลาสใดก็ได้ (สังเกตว่าเมธอดเป็นแบบคงที่)
Sydwell

1
ตกลงฉันแค่อยากจะแน่ใจ ขอบคุณสำหรับรหัสที่ดีนี้
เบญจ

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

ในข้างต้นใช้ e.getStackTrace () [0] ในฟังก์ชันตัวจัดการของคุณ (fShowUncaughtMessage) เพื่อรับตัวผู้กระทำความผิด


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นี้ (แต่สำหรับ Android)

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

ป้อนคำอธิบายภาพที่นี่

คลิกเพียงครั้งเดียวที่ข้อความที่ขีดเส้นใต้เพื่อนำทางไปยังตำแหน่งที่คำสั่งบันทึกอยู่

ที่StackTraceElementกำหนดโดยองค์ประกอบแรกภายนอกไลบรารีนี้ ดังนั้นที่ใดก็ได้นอก lib นี้จะเป็นทางกฎหมายรวมทั้งlambda expression, static 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.