Trình ghi nhật ký có nên là tĩnh riêng tư hay không


103

Loggger có nên được khai báo static hay không? Thông thường tôi đã thấy hai kiểu khai báo cho trình ghi nhật ký:

    bảo vệ Log log = new Log4JLogger (aClass.class);

hoặc là

    private static Log log = new Log4JLogger (aClass.class);

Cái nào nên được sử dụng? chuyên nghiệp và con của cả hai là gì?


1
Khai thác gỗ là một mối quan tâm xuyên suốt. Sử dụng Các khía cạnh và câu hỏi là tranh luận.
Dave Jarvis

4
staticlà một tham chiếu cho mỗi lớp. non-static là một tham chiếu cho mỗi trường hợp (+ khởi tạo). Vì vậy, trong một số trường hợp, phần sau có tác động đáng kể đến bộ nhớ nếu bạn có rất nhiều trường hợp. Không bao giờ sử dụng không tĩnh trong một đối tượng thường xuyên . Tôi luôn sử dụng phiên bản tĩnh. (mà phải được uppercased LOG )
Có QUIT - Anony-Mousse

2
như đã được đề xuất, hãy sử dụng AOP và chú thích, ví dụ: jcabi.com/jcabi-aspects/annotation-loggable.html
yegor256

1
RobertHume phiên bản tĩnh đang sử dụng một hằng số. Đó chính xác là lý do tại sao nó nên được viết hoa.
Có QUIT - Anony-Mousse

2
Không, nó phải private static final Log loglà chữ thường. Bộ ghi nhật ký không phải là một hằng số, bộ ghi nhật ký là một đối tượng cuối cùng tĩnh (có thể bị thay đổi). Cá nhân tôi luôn sử dụng logger.
osundblad

Câu trả lời:


99

Ưu điểm của biểu mẫu không tĩnh là bạn có thể khai báo nó trong một lớp cơ sở (trừu tượng) như sau mà không cần lo lắng rằng tên lớp phù hợp sẽ được sử dụng:

protected Log log = new Log4JLogger(getClass());

Tuy nhiên, nhược điểm của nó rõ ràng là một thể hiện hoàn toàn mới sẽ được tạo cho mọi thể hiện của lớp. Điều này có thể không đắt, nhưng nó làm tăng thêm chi phí đáng kể. Nếu bạn muốn tránh điều này, bạn muốn sử dụng staticbiểu mẫu thay thế. Nhưng nhược điểm của nó là bạn phải khai báo nó trong mọi lớp riêng lẻ và chú ý trong mọi lớp rằng tên lớp phù hợp được sử dụng trong quá trình xây dựng trình ghi nhật ký vì getClass()không thể được sử dụng trong ngữ cảnh tĩnh. Tuy nhiên, trong IDE trung bình, bạn có thể tạo một mẫu tự động hoàn thành cho việc này. Ví dụ: logger+ ctrl+space.

Mặt khác, nếu bạn có được trình ghi nhật ký bởi một nhà máy có thể lưu vào bộ nhớ cache của các trình ghi nhật ký đã được khởi tạo sẵn, thì việc sử dụng biểu mẫu không tĩnh sẽ không thêm nhiều chi phí như vậy. Ví dụ như Log4j có LogManagermục đích này.

protected Log log = LogManager.getLogger(getClass());

6
Khai báo abstract Log getLogger();trong lớp trừu tượng. Triển khai phương thức này, trả về trình ghi nhật ký tĩnh cho phiên bản cụ thể. Thêm vào private final static Log LOG = LogManager.getLogger(Clazz.class);mẫu lớp IDE của bạn.
Có QUIT - Anony-Mousse

2
Đối với slf4j:protected Logger log = LoggerFactory.getLogger(getClass());
Markus Pscheidt

3
@BalusC vấn đề khi truyền getClass () cho phương thức getLogger là nó trả về lớp của cá thể hiện tại. Thông thường, việc ghi nhật ký được liên kết với lớp mã ở đó là mong muốn hơn. Ví dụ: nếu mã ghi nhật ký nằm trong lớp Parent thì chúng tôi muốn ghi nhật ký được liên kết với Parent mặc dù thể hiện đang thực thi là và thể hiện của lớp Child là lớp con của Parent. Với getClass (), nó sẽ được liên kết với Child, không chính xác
inor

@inor: "không chính xác"? Nếu bạn không muốn trừu tượng lớp, thì bạn không nên sử dụng getClass () kế thừa ngay từ đầu. Có những nhà phát triển thấy nó đúng và hữu ích vì nó tiết lộ thông tin mà lớp con chính xác logic đã được thực hiện.
BalusC

2
@ BalusC getLogger (getClass ()) dẫn đến việc luôn ghi sai tên của lớp con. Các lớp ghi nhật ký phải luôn làm getLogger (Clazz.class) để liên kết việc ghi nhật ký được tạo bởi mã trong lớp Clazz. Các nhà phát triển muốn biết lớp con nào đang thực thi (Ví dụ: SubClazz mở rộng Clazz) nên thực hiện trong SubClazz: getLogger (SubClazz.class) và một cái gì đó như: log.info ("gọi <cái gì đó trong lớp cơ sở của tôi>");
inor

44

Tôi từng nghĩ rằng tất cả các log phải tĩnh; tuy nhiên, bài viết này tại wiki.apache.org đưa ra một số lo ngại quan trọng về bộ nhớ, liên quan đến rò rỉ bộ nạp lớp. Việc khai báo trình ghi là tĩnh ngăn lớp khai báo (và các bộ nạp lớp liên quan) được thu gom rác trong các vùng chứa J2EE sử dụng bộ nạp lớp dùng chung. Điều này sẽ dẫn đến lỗi PermGen nếu bạn triển khai lại ứng dụng của mình đủ lần.

Tôi thực sự không thấy bất kỳ cách nào để giải quyết vấn đề rò rỉ bộ nạp lớp này, ngoài việc khai báo các trình ghi nhật ký là không tĩnh.


4
Tôi nghi ngờ trường tĩnh cũng sẽ có vấn đề rò rỉ bộ nhớ. Không tĩnh có thể có vấn đề về hiệu suất như những người khác đã nói. Cách lý tưởng sau đó là gì?
liang

@piepera vấn đề chính được mô tả trong bài viết mà bạn đã tham khảo là khả năng kiểm soát cấp độ ghi nhật ký trong mỗi ứng dụng khi "xem xét trường hợp khi một lớp sử dụng" private static Log log = "được triển khai thông qua ClassLoader nằm trong tổ tiên của nhiều ứng dụng được cho là "ứng dụng" "độc lập. Tôi không thấy đó là một vấn đề bởi vì trong tình huống cụ thể này, các ứng dụng có "điểm chung" và trong "điểm chung" đó, cấp độ ghi nhật ký cho lớp được quyết định và vâng, nó giữ cho tất cả các ứng dụng ... nhưng hãy giữ lưu ý rằng lớp này được [tải] bên ngoài các ứng dụng này
vào

17

Sự khác biệt quan trọng nhất là nó ảnh hưởng đến các tệp nhật ký của bạn như thế nào: nhật ký đi vào danh mục nào?

  • Trong lựa chọn đầu tiên của bạn, nhật ký của một lớp con kết thúc trong danh mục của lớp cha. Điều đó có vẻ rất phản trực giác đối với tôi.
  • Có một biến thể của trường hợp đầu tiên của bạn:

    bảo vệ Log log = new Log4JLogger (getClass ());

    Trong trường hợp đó, danh mục nhật ký của bạn cho biết mã đã ghi nhật ký đang hoạt động trên đối tượng nào.

  • Trong lựa chọn thứ hai của bạn (tĩnh riêng), danh mục nhật ký là lớp có chứa mã ghi nhật ký. Vì vậy, bình thường lớp đang làm điều được ghi nhật ký.

Tôi thực sự khuyên bạn nên lựa chọn cuối cùng. Nó có những ưu điểm này, so với các giải pháp khác:

  • Có một mối quan hệ trực tiếp giữa nhật ký và mã. Thật dễ dàng để tìm lại nơi xuất phát thông báo nhật ký.
  • Nếu ai đó phải điều chỉnh mức độ ghi nhật ký (được thực hiện theo từng danh mục), đó thường là do họ quan tâm (hoặc không) trong một số thư cụ thể, được viết bởi một lớp cụ thể. Nếu danh mục không phải là lớp đang viết thông báo, thì việc điều chỉnh các mức sẽ khó hơn.
  • Bạn có thể đăng nhập các phương thức tĩnh
  • Bộ ghi nhật ký chỉ cần được khởi tạo (hoặc tra cứu) một lần cho mỗi lớp, vì vậy khi khởi động, thay vì cho mọi phiên bản được tạo.

Nó cũng có những nhược điểm:

  • Nó cần phải được khai báo trong mọi lớp mà bạn ghi nhật ký thông báo (không sử dụng lại trình ghi nhật ký siêu lớp).
  • Bạn cần chú ý đặt đúng tên lớp khi khởi tạo trình ghi nhật ký. (Nhưng IDE tốt sẽ lo điều đó cho bạn).

4

Sử dụng đảo ngược điều khiển và chuyển trình ghi nhật ký vào phương thức khởi tạo. Nếu bạn tạo trình ghi nhật ký bên trong lớp, bạn sẽ gặp khó khăn với các bài kiểm tra đơn vị của mình. Bạn đang viết bài kiểm tra đơn vị phải không?


5
Các bài kiểm tra đơn vị kiểm tra việc ghi nhật ký bạn đang tạo ra âm thanh vừa vô dụng vừa cực kỳ giòn.
Michael

1
Tính hữu dụng tùy thuộc vào hệ thống đang thử nghiệm. Đôi khi việc ghi nhật ký là tất cả những gì bạn có quyền truy cập.
Wayne Allen

@Wayne Allen khi bạn đang thực hiện các bài kiểm tra đơn vị, theo định nghĩa, bạn cũng có kết quả kiểm tra. Bạn đang đề xuất một tình huống trong đó một bài kiểm tra đơn vị nhưng không có kết quả kiểm tra? chỉ có các bản ghi?
Inor 20/02/18

tạo trình ghi bên trong lớp không tạo ra vấn đề. Bạn có thể chỉ ra một ví dụ đơn giản khó UT vì lớp tạo ra trình ghi nhật ký của riêng nó không?
Inor 20/02/18

1
Chắc chắn rồi. Làm thế nào về một trình ghi nhật ký gửi email. Không muốn làm điều đó mỗi khi bạn chạy thử nghiệm của mình. Thêm vào đó làm thế nào để bạn khẳng định tác dụng phụ?
Wayne Allen,
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.