Logger.getLogger (MyClass. Class) có phải là cách tốt nhất để khởi tạo logger log4j không?


13

Hướng dẫn Mkyong này gợi ý các logger intialising theo cách này:

@Controller
public class WelcomeController {

    private static final Logger logger = Logger.getLogger(WelcomeController.class);

   // etc

}

Bây giờ có lẽ là tất cả các lớp khác mà bạn sử dụng, có một logger sẽ khởi tạo logger của chúng theo cùng một cách.

Câu hỏi của tôi là - đây có phải là cách tốt nhất để làm điều đó? Có vẻ như ... lặp đi lặp lại.


2
Bạn thấy gì dài dòng về điều này (đặt cú pháp của Java sang một bên)?. Bạn phải tạo một biến để giữ logger và bạn phải cho biết getLogger()tên của logger để lấy.
kdgregory

2
@kdgregory thực tế là tôi đang làm điều tương tự trong mỗi lớp.
dwjohnston

1

3
Quá cũ để di chuyển, nhưng câu hỏi này không có chủ đề ở đây và phù hợp hơn với StackOverflow.
Andres F.

1
@AresresF. Tôi nghĩ rằng tôi đặt nó ở đây bởi vì đó là một câu hỏi về phong cách thiết kế / mẫu mã, hơn là một vấn đề kỹ thuật.
dwjohnston

Câu trả lời:


16

Nhận xét của bạn nói rằng "verbose" đề cập đến sự cần thiết phải lặp lại dòng mã này trong mỗi lớp. Phản hồi đầu tiên của tôi là, trong bức tranh lớn, việc thêm hai dòng mã (định nghĩa biến cộng với câu lệnh nhập) vào mỗi lớp không phải là vấn đề lớn. Đặc biệt là vì bạn chỉ cần thêm chúng vào các lớp có hành vi và do đó cần phải đăng nhập. Điều đó nói rằng, dòng mã cụ thể mà bạn đang sử dụng có xu hướng sao chép-dán lỗi (nhiều hơn về sau).

Nhưng, vì bạn muốn có các lựa chọn thay thế, đây là một vài lý do mà bạn có thể muốn hoặc không muốn sử dụng chúng.

Sử dụng một logger duy nhất cho toàn bộ ứng dụng

Nếu bạn không quan tâm đến những gì lớp đang báo cáo, hoặc sẵn sàng đưa tất cả bối cảnh cần thiết vào tin nhắn, thì một trình ghi nhật ký đơn giản sẽ thực hiện công việc:

LoggerSingleton.getInstance().debug("MyController is running")

Theo tôi, một trong những lợi ích lớn của khung đăng nhập là có bối cảnh được cung cấp bởi các phiên bản logger riêng biệt - nếu chỉ để hướng các thông điệp tường trình đến các đích khác nhau. Tôi sẽ không từ bỏ chỉ để lưu một dòng mã (bạn vẫn cần nhập).

Thêm vào đó, điều này làm tăng tính dài dòng tại điểm sử dụng, điều này sẽ kết thúc bằng nhiều lần nhấn phím hơn.

Tạo logger của bạn tại điểm sử dụng

Tôi ném cái này ra chỉ vì nó loại bỏ biến. Tôi không nghĩ rằng tôi cần bình luận về nó. Mặc dù nó cho thấy kỹ thuật ưa thích của tôi để lấy một cá thể logger.

Logger.getLogger(getClass()).debug("blah blah blah");

Sử dụng một bộ xử lý hậu đậu để tiêm logger

Ví dụ của bạn sử dụng Spring và Spring cho phép bạn nối vào mã khởi tạo bean. Bạn có thể tạo một bộ xử lý hậu kiểm tra bean cho một loggerbiến thành viên và tạo một Loggercá thể khi nó tìm thấy một biến.

Mặc dù bộ xử lý hậu như vậy chỉ có vài chục dòng mã, nhưng đó là một phần chuyển động khác trong ứng dụng của bạn và do đó là một nguồn lỗi tiềm năng khác. Tôi thích có càng ít trong số đó càng tốt.

Sử dụng hỗn hợp

Scala và Groovy cung cấp các đặc điểm , cho phép bạn gói gọn hành vi. Một mẫu Scala điển hình là tạo một Loggingđặc điểm, sau đó thêm nó vào lớp cần ghi nhật ký:

class MyController with Logging

Thật không may, điều này có nghĩa là bạn phải chuyển đổi ngôn ngữ. Trừ khi bạn đang sử dụng Java 8, trong trường hợp đó bạn có thể tạo Logginggiao diện với "phương thức mặc định":

public interface Logging {
    default Logger getLogger() {
        return Logger.getLogger(getClass());
    } 
}

Bây giờ, trong mã lớp của bạn, bạn chỉ cần sử dụng

getLogger().debug("blah blah blah");

Trong khi dễ dàng, điều này có một vài nhược điểm. Đối với một điều, nó gây ô nhiễm giao diện của mọi lớp sử dụng nó, bởi vì tất cả các phương thức giao diện là công khai. Có lẽ không tệ nếu bạn chỉ sử dụng nó cho các lớp được khởi tạo và chèn bởi Spring, đặc biệt nếu bạn tuân theo phân tách giao diện / triển khai.

Vấn đề lớn hơn là nó phải tra cứu phiên bản logger thực tế trên mỗi cuộc gọi. Cái nào nhanh, nhưng không cần thiết.

Và bạn vẫn cần một báo cáo nhập khẩu.

Di chuyển logger đến một siêu lớp

Tôi sẽ lặp lại: Tôi không tìm thấy các định nghĩa logger lặp đi lặp lại, nhưng nếu bạn nghĩ rằng đây là cách tiếp cận tốt nhất để loại bỏ chúng.

public abstract class AbstractController {
    protected Logger logger = Logger.getLogger(getClass());
}

Bây giờ các lớp trình điều khiển của bạn kế thừa từ AbstractControllervà chúng có quyền truy cập vào loggerbiến. Hãy nhớ rằng bạn phải đặt @Controllerchú thích vào lớp cụ thể.

Một số người sẽ thấy đây là một sự đồi bại của thừa kế. Tôi đã cố gắng làm dịu chúng bằng cách đặt tên cho lớp AbstractControllerchứ không phải AbstractProjectClass. Bạn có thể tự quyết định xem có hay không một mối quan hệ.

Những người khác sẽ phản đối việc sử dụng một biến thể hiện hơn là một biến tĩnh. Trình ghi nhật ký tĩnh IMO dễ bị lỗi sao chép-dán, vì bạn phải tham chiếu rõ ràng tên lớp; getClass()đảm bảo rằng logger của bạn luôn luôn chính xác.


Tôi nghĩ bạn nên cẩn thận về getClass () trong lớp kế thừa, MethodHandles.lookup (). LookupClass () sẽ tốt hơn sau jdk 7
yuxh

@luxh - bạn có giải thích cho điều đó không?
kdgregory

kiểm tra tại đây: stackoverflow.com/a/6653577/4652536
yuxh

@yuxh - đề cập duy nhất về Phương thức trong câu hỏi đó (không có trong câu trả lời bạn đã liên kết), là một xác nhận không được hỗ trợ tương tự với một nhận xét yêu cầu làm rõ. Bạn có hỗ trợ có thẩm quyền cho khẳng định đó MethodHandles.lookup().lookupClass()là tốt hơn Object.getClass()?
kdgregory

MethodHandles.lookup().lookupClass()có thể được sử dụng cho các biến tĩnh, không dễ bị sao chép-dán lỗi và nhanh chóng: stackoverflow.com/a/47112323/898747 Nó có nghĩa là một Xuất nhập thêm, nhưng tôi khá giống như logger tôi Bein tĩnh nên nó là ít nhất một giá trị đề cập :)
FableBlaze

0

Để mở rộng câu trả lời được cung cấp bởi @kdgregory, Groovy cung cấp @Slf4j( groovy.util.logging.Slf4j) ngoài hộp dưới dạng một chú thích thực hiện chuyển đổi AST trên lớp để xử lý nó bằng một logger mặc định giả sử tên biến logtheo mặc định nếu không được chỉ định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.