2013-07-04 37 views
24

Có cách nào trong Java tự động lấy số dòng hiện tại thông qua phản xạ hoặc một số API tuyệt vời không? Cũng giống như khi ngoại lệ xảy ra, số dòng được in ra trong dấu vết ngăn xếp như thế này:Tự động lấy số dòng hiện tại

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

Bây giờ có cách in hoặc ghi như trong mã dưới đây không?

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

Bạn có thể hỏi, tại sao tôi không chỉ cần in số dòng? Cũng vì mã có thể bị xóa hoặc được thêm vào trước khi gọi phương thức log.error() cụ thể.

+2

Không PatternLayout ghi nhật ký API có tiện dụng cho việc này không? – sadhu

+0

Bạn có thể tạo ra một 'mới Throwable' và truy cập các yếu tố theo dõi stack. Xem http://stackoverflow.com/questions/115008/how-can-we-print-line-numbers-to-the-log-in-java –

+2

@Andreas: bạn không cần một 'Throwable': [' Thread.getStackTrace() '] (http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#getStackTrace()) là đủ. –

Trả lời

7

tôi đã có thể sử dụng Thread.currentThread() getStackTrace() phương pháp để tạo ra một tập hợp các chức năng mà làm việc cùng nhau để tạo ra số dòng của mã đó được gọi là phương pháp đầu tiên, như vậy:.

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

Hy vọng điều này sẽ hữu ích! Tôi đặt chúng trong một lớp tiện ích để chúng được ra khỏi con đường, nhưng vẫn dễ dàng truy cập. Phương pháp thứ hai là riêng tư để ngăn chặn bất kỳ phương pháp nào khác ngoài phương pháp đầu tiên gọi nó để nó luôn hoạt động chính xác.

+0

Tốt nhất, cái này phải là câu trả lời được chấp nhận. –

34

Bạn có thể tạo một Throwable và sử dụng nó StackTraceElements:

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

Như @Joachim nói, bạn cũng có thể sử dụng Thread.getStackTrace(), ví dụ như

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

Hãy nhận biết rằng cách tiếp cận thứ hai trả về một mảng hơi khác - bạn cần phải sử dụng các phần tử mảng với chỉ số 1 để có được số dòng hiện, vì nó bao gồm các cuộc gọi đến getStackTrace() chính nó như là người đầu tiên thành phần.

Cũng lưu ý các nhận xét về Ghi nhật ký và hiệu suất từ ​​câu trả lời của @ Joachim.

+1

Có thể mang lại kết quả khác nhau trên một số JVM. Ít nhất là trên IBM JVM cho AIX ngăn xếp bao gồm các nhà thầu có thể ném được. Xem javadoc của getStackTrace: 'Phần tử con của mảng (giả sử chiều dài của mảng là khác không) biểu thị phần trên cùng của ngăn xếp, đó là lời gọi phương thức cuối cùng trong chuỗi. Thông thường, đây là điểm mà tại đó ném này đã được tạo ra và ném. '- thường, không được bảo đảm. Vì vậy, giải pháp của Brian_Entei linh hoạt hơn. –

15

Trước hết: Nếu bất kỳ điều gì, thì mẫu ghi nhật ký (hoặc trang trí hoặc bất kỳ khung đăng nhập nào của bạn gọi phần đó) nên thực hiện việc này. Cuộc gọi nhật ký trong mã của bạn chỉ nên chỉ ghi thông tin doanh nghiệp thực tế. Thông tin về nơi cần được thêm vào bởi trình ghi nhật ký.

Tiếp theo: nhận được loại hoạt động đó là tốn kém (về mặt thời gian), bởi vì Java không được tối ưu hóa cho việc này. Khi chạy, JVM cần kiểm tra trạng thái của nó, tải/phân tích cú pháp thông tin gỡ lỗi và tìm số dòng tương ứng với một lệnh đã cho. Đó là lý do tại sao loại thông tin này thường chỉ được đưa ra khi một ngoại lệ xảy ra (trong trường hợp này chúng tôi đã gặp sự cố và biết rằng thời gian dành cho thường sẽ đáng giá).

Và cuối cùng nhưng không kém: nếu vì một số lý do bạn cần thông tin đó, bạn có thể sử dụng Thread.getStackTrace() và kiểm tra số StackTraceElement thứ hai trên đó.

0

Bạn cũng có thể nhận được số dòng Ngoại lệ bằng đoạn mã sau. Sử dụng phương thức util sau trong lớp util của bạn.

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

Từ khối catch bạn có thể gọi như dưới đây:

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

Hope làm việc này! :)

Các vấn đề liên quan