2009-10-22 3 views
5

Giống như nhiều người dùng log4j, chúng tôi thường có bản ghi mức độ gỡ lỗi tốn kém để đánh giá. Vì vậy, chúng tôi bảo vệ những trường hợp đó bằng mã như:Thực hiện các sửa đổi hiệu suất đơn giản đối với một lọ đã được biên dịch?

if(_logger.isDebugEnabled) 
    _logger.debug("Interesting, my foojes are goofed up: " + getFullDetails()) 

Tuy nhiên, đó là xấu hơn lời gọi _logger.debug đơn giản và đôi khi người lập trình không nhận ra đánh giá có thể tốn kém.

Có vẻ như sẽ khá đơn giản để viết một chương trình cần một biên dịch jar và bảo vệ tất cả các cuộc gọi _logger.debug với kiểm tra isDebugEnabled. Chúng tôi có thể sẵn sàng chấp nhận thêm chi phí kiểm tra làDebugEnabled trong mọi trường hợp.

Có ai đã thử cách tiếp cận này hoặc thực hiện quá trình xử lý sau bình tương tự không?

+0

Tôi không chắc chắn rằng log4j không làm điều đó đã (kiểm tra nội bộ đó làDebugEnabled = true trước khi in một công cụ đánh giá lớn và dài) ... bạn đã kiểm tra chưa? –

+1

log4j không kiểm tra chính mức nhật ký (tất nhiên). Lý do tại sao mọi người đang sử dụng cờ 'isDebugEnabled()' là họ muốn tránh nguyên nhân gây ra bởi việc xây dựng các chuỗi ('" Thú vị, các fooj của tôi được goofed lên: "+ getFullDetails()' trong ví dụ) và tương tự . – sfussenegger

+1

log4j không kiểm tra isDebugEnabled đầu tiên. Tôi đang cố gắng để tránh đánh giá getFullDetails nếu Debug không được kích hoạt. –

Trả lời

2

Bạn đã xem AspectJ chưa? Điều này hỗ trợ các khía cạnh bằng cách sử dụng tính năng dệt bytecode và có thể can thiệp into a previously compiled .jar file.

+0

Rất hữu ích, điều này là gần nhất với những gì tôi đang tìm kiếm. –

+0

Tôi không thấy làm thế nào điều này giúp với ví dụ kiểm tra. Thậm chí nếu bạn đặt một dấu cắt trên 'Logger.debug (String)' với lời khuyên 'around' để ngăn chặn nó được gọi,' getFullDetails() 'sẽ vẫn được gọi. – McDowell

4

Thay vì xem xét sửa đổi bình, tôi sẽ tìm kiếm giải pháp sử dụng Bytecode Instrumentation. Vấn đề sẽ là xác định các phần của mã bạn muốn bọc bên trong một .isDebugEnabled() - bạn sẽ phải xác định các đối tượng chỉ được sử dụng cho các lời gọi log4j.

+0

Tôi đoán bạn có thể quay lại từ 'ivokevirtual' trên' debug' để tìm lệnh 'getfield' có logger. Có thể có những trường hợp không rõ ràng khi cuộc gọi đăng nhập bắt đầu và kết thúc. Nó là giá trị điều tra. – McDowell

1

Tôi tin rằng giải pháp tốt sẽ là mã sẽ có hiệu quả như.

Hãy xem xét rằng log4j không còn được dùng nữa. Chính tác giả của nó đã để nó như vậy, để tránh phá vỡ tính tương thích, nhưng ông đã tạo ra một cái mới, SLF4J (http://www.slf4j.org/). Ông cung cấp cả một mặt tiền và thực hiện, theo sự phân biệt commons-logging/log4j, nhưng không có những sai sót của mỗi ...

Tôi tin rằng, trong cơ sở khai thác mới này, bạn có thể gửi các tham số đối tượng để ghi nhật ký và mức đó được đánh giá trước khi chuyển đổi các đối tượng (thành chuỗi hoặc theo cách khác). Ý tưởng là sử dụng chuỗi định dạng và tham số.


Mã của chúng tôi không sử dụng slf4j, nhưng chúng tôi có các phương pháp tiện ích thực hiện chính xác điều đó. Nó được mã hóa xấp xỉ như sau (từ bộ nhớ):

public enum LogLevel { 
     FATAL, ERROR, WARNING, INFO, DEBUG; 

     public void log(Logger logger, String format, Object... parameters) { 
     if (isEnabled(logger)) { 
      logImpl(logger, String.format(format, parameters)); 
     } 
     } 
     public boolean isEnabled(Logger logger) { 
     switch(this) { 
      case WARNING : return logger.isWarningEnabled(); 
      case INFO : return logger.isInfoEnabled(); 
      case DEBUG : return logger.isDebugEnabled(); 
      default: return true; 
     } 
     } 
     private void logImpl(Logger logger, String message) { 
     switch(this) { 
      case WARNING : logger.warn(message); 
      // other cases 
     } 
     } 
    } 

Nó được sử dụng như:

 public void myMethod(Object param) { 
     LogLevel.WARNING.log(LOGGER, "What is my message ....", "myMethod", param); 
    } 

CẬP NHẬT: Nếu bạn cần gọi một phương thức trong nhật ký .. .

  • Một khả năng là sử dụng phương thức toString. Điều này là thích hợp nếu nhật ký của bạn là 'kỹ thuật' và cũng sẽ được sử dụng khi gỡ lỗi.

  • Nếu đăng nhập của bạn là thêm chức năng (không nhắm mục tiêu đến developper), tôi đề nghị để xác định một giao diện (đó là chức năng âm thanh trong trường hợp đó, vì vậy nó rất hữu ích để cung cấp ý nghĩa):

    public interface Detailable { // the name could also suggest logging? 
        String getFullDetails(); 
    } 
    

    Triển khai giao diện đó trong bất kỳ đối tượng nào cần được truyền dưới dạng đối tượng ghi nhật ký, với tính toán phức tạp để tạo nhật ký.

+0

Việc truyền các đối tượng vào cuộc gọi ghi nhật ký không giúp ích gì. Chi phí là trong việc đánh giá getFullDetails. –

+1

@Ted, nếu bạn thay đổi getFullDetails để cung cấp một đối tượng thực hiện đánh giá trong phương thức toString của nó có thể trì hoãn hiệu quả công việc. Điều đó sẽ giúp tất cả các trường hợp ngoại trừ nơi "lập trình viên không nhận ra rằng việc đánh giá có thể tốn kém." – Yishai

+0

Bạn có thể để một cái gì đó như thế này: 'log.debug (" Thú vị, foojes của tôi được goofed lên: {} ", new Object() {String toString() {return getFullDetails());' - nhưng là đẹp hơn nguyên? :) – sfussenegger