2010-06-22 4 views
5

Tôi có một số mã Java mà tôi muốn sử dụng với các thông điệp tường trình cho mục đích gỡ lỗi. Mã sản xuất cuối cùng (biên dịch), tuy nhiên, không nên chứa bất kỳ đăng nhập nào vì nó sẽ làm chậm thời gian thực hiện. Có cách nào trong Java để vô hiệu hóa một logger tại thời gian biên dịch?Tắt đăng nhập Java tại thời gian biên dịch

Tôi không sợ dấu kiểm bên trong phương thức nhật ký của trình ghi nhật ký bật/tắt được kích hoạt trong thời gian chạy sẽ thêm.

if (logging==enabled) {// do logging} 

Nhưng tôi muốn tránh xây dựng tham số như sau trong mã sản xuất của tôi:

Logger.log("undefined state" + state + " @ " + new Date()); 

Tôi đang sử dụng Java Compiler mặt trời.

Trả lời

0

Tôi không biết về bất kỳ chức năng Trình biên dịch nào về điều này, nhưng những gì bạn cũng có thể làm là tạo một tập lệnh xây dựng. Kịch bản lệnh này sẽ sao chép các tệp nguồn Java gốc (gỡ lỗi), sao chép chúng vào một vị trí tạm thời, loại bỏ các khai báo đăng nhập khỏi chúng và sau đó biên dịch các tệp nguồn mới mà sau đó không có mã gỡ lỗi.

1

Không có cách nào được tích hợp sẵn để thực hiện điều này. Bạn có thể muốn sử dụng một số Java Preprocessor.

+0

Tôi nghĩ như vậy khi tôi đã googling ... – Max

2
if(logger.isDebugEnabled()) { 
    logger.debug(expression); 
} 

Mọi khung đăng nhập tôi đã sử dụng yêu cầu bạn sử dụng mẫu trên để tránh đánh giá không cần thiết về biểu thức ghi nhật ký.

+2

tra {} -placeholders trong slf4j. –

+0

@ Thorbjørn Ravn Andersen - gọn gàng - rõ ràng là tốt hơn cho nhiều trường hợp sử dụng. Tôi muốn nitpick về instantiation mảng đối tượng, tiềm năng cho autoboxing không cần thiết và như vậy, nhưng nhiều trong số đó nên được JIT biên dịch đi vào thời gian chạy anyway. API slf4j không loại trừ việc sử dụng bộ phận bảo vệ boolean khi cần thiết._ – McDowell

+0

Đó là vấn đề về hương vị. Đối với tôi, {} chú thích dẫn đến ít mã hơn (không nếu) và ít lộn xộn hơn (không có chuỗi nối). –

1

Một cách là thực hiện kiểm tra bên ngoài phương thức đăng nhập. Hầu như kiểm tra tương tự như bạn đã đề cập, nhưng bạn tự làm như vậy:

if (LOGGER.isLoggable(Level.DEBUG)) { 
    LOGGER.log("undefined state" + state + " @ " + new Date()); 
} 

Phương pháp này có thể được sử dụng với bất kỳ mức ghi nào. xem Logger#isLoggable(Level) để biết thêm thông tin. Lưu ý rằng đó là cách được khuyến nghị để tránh việc xây dựng tham số phương thức log.

+0

Bạn đã đánh bại tôi trong trò chơi này! – Riduidel

+0

Nội tuyến các cuộc gọi đăng nhập không phải là lựa chọn ưa thích của tôi, vì nó cho biết thêm rất nhiều lộn xộn. – Max

+0

sau đó các tùy chọn đang xử lý trước nguồn hoặc sử dụng những thứ như AOP để thêm ghi nhật ký khi bạn cần. – unbeli

0

Một hack xấu xí mà có thể làm việc là để che giấu sự thực hiện của thư viện Logger với một thực hiện rỗng. Trình tối ưu hóa sẽ đặt nội tuyến và xóa mã deadcode nên xóa cấu trúc tham số. Điều này sẽ không hoạt động khi cấu trúc tham số chứa các tác dụng phụ.

Bây giờ đây là lý thuyết, tôi chưa thử nghiệm điều này trong thực tế. Tôi tò mò về điều này mặc dù. Có lẽ điều này đảm bảo một câu hỏi riêng biệt?

+0

Tôi đã không chắc chắn liệu trình biên dịch sẽ được "thông minh", đủ để optmise đó. Tôi có thể dùng thử ... – Max

+0

Trình biên dịch dường như không tối ưu hóa mã. Thời gian thực hiện để gọi một phương thức rỗng trong khi truyền một chuỗi tĩnh so với một phương thức đã được nối với nhau theo thứ tự độ lớn (ít nhất là không có tùy chọn trình biên dịch đặc biệt nào được bật). – Max

+0

Trong mọi trường hợp, tôi sẽ không dựa vào nó. Tôi cOnfigured IDE của tôi để mở rộng 'logd' để nếu (log.isDebugEnabled()) {log.debug ("yadayada");} và vv. –

0

Bạn thực sự nên sử dụng chỉ báo Mức cho thông điệp tường trình của mình, Cấp độ.SEVERE -> Cấp độ.FINEST.

Có nhiều phương pháp xác định trước trong Logger cho ví dụ này:

Logger.info(msg); 
Logger.finest(msg); // debug/trace message. 

Logger.log(Level.CONFIG, "config message"); 

này sẽ cho phép bạn cấu hình mức ghi minumim ở cấp ứng dụng và bật/tắt những thông điệp dưới mức cấu hình, sử dụng lệnh dòng, tệp cấu hình hoặc bằng cách sử dụng LogManager

+0

Chắc chắn, nhưng nếu bạn muốn chuyển vào một chuỗi được xây dựng (xem ví dụ của tôi), việc xây dựng sẽ được gọi trước khi kiểm tra mức độ đăng nhập. – Max

+0

Bạn có thể viết một tham số chèn thực hiện của riêng bạn, sử dụng varargs, để sử dụng với khai thác gỗ kiểm tra hiện tại nd mong muốn loglevel. Ngoài ra, hãy kiểm tra log4j hoặc slf4j –

5

Bạn đã xem xét phương pháp tiếp cận slf4j với {} -placeholders. Điều đó cho phép xây dựng chậm của toString() có nghĩa là log.debug (...) là rẻ nếu việc ghi nhật ký gỡ lỗi bị vô hiệu hóa.

log.debug("in loop() - a={}, b={}", a, b); 
+0

Có, tôi đã xem xét phương pháp này để chuyển tất cả các tham số và xây dựng chúng sau khi kiểm tra, nhưng tôi vẫn hy vọng nhận được phản hồi tích cực khi xử lý ở mức biên dịch. Đây là cách ưa thích của tôi vào lúc này. – Max

+1

Sau đó, xem xét câu lệnh khẳng định cho phép bạn tắt hoàn toàn các phần mã. Thật không may là slf4j API trả về void vì vậy chúng không thể được sử dụng với điều này - bạn sẽ phải cuộn wrapper của riêng bạn. –

0

Tôi hiểu rằng trình biên dịch Java có thể loại bỏ các khối mã được bảo vệ bởi biểu thức hằng số thời gian biên dịch. Vì vậy, về mặt lý thuyết, bạn sẽ có thể làm điều này với một cái gì đó như thế này:

public class Logging { 
    public static final boolean ENABLED = true; // change to false 
} 

public class Something 
    .... 

    if (Logging.ENABLED) { 
      logger.debug("hello mum"); 
    } 
} 

Thật không may, bạn cần phải biên dịch lại mỗi lớp mà phụ thuộc vào lá cờ Logging.ENABLED bất cứ khi nào bạn thay đổi giá trị của nó. Vì vậy, tôi rất thích những điều sau đây:

public class Something 
    .... 

    if (logger.isDebugEnabled()) { 
      logger.debug("hello mum"); 
    } 
} 

có lợi thế là bạn có thể thực hiện các điều chỉnh chi tiết cho mức ghi nhật ký tại thời gian cấu hình hoặc ngay cả khi chạy; ví dụ. bằng cách sử dụng trình gỡ lỗi, JMX, v.v. Ngoài ra, chi phí gọi số logger.isDebugEnabled() trong log4j đủ thấp khiến bạn không thể nhận thấy trừ khi bạn có số lượng đăng nhập không chính xác trong mã nguồn của mình.

2

Có thể xử lý các tệp lớp java bằng cách sử dụng Proguard và sử dụng tùy chọn -assumenosideeffects để xóa các cuộc gọi ghi nhật ký. Này được thực hiện phổ biến nhất dành cho Android sử dụng:

-assumenosideeffects class android.util.Log { 
    public static *** d(...); 
    public static *** v(...); 
} 

loại bỏ tất cả các cuộc gọi đến Log.d(TAG, "message"), vv ...

+0

Chào mừng bạn đến với phong cách yêu cầu SO.Your của bạn là tốt bằng cách sử dụng mã trong câu hỏi của bạn là prectice tốt – khan