Câu hỏi Ghi nhật ký Java với lớp trừu tượng


Tôi đang làm việc trên một dự án, và hiện đang làm việc trên thực hiện một số đăng nhập với log4j và tôi đã tò mò về cách tôi nên đi về việc thực hiện các bản ghi. Hai triển khai tôi đang đá xung quanh như sau:

Lựa chọn đầu tiên 

Sử dụng nhật ký đơn từ siêu lớp cho lớp đó và tất cả các lớp con:

public abstract class AbstractFoo {
    protected static Log LOG = LogFactory.getLog(AbstractFoo.class);

    ...
}

public class Foo extends AbstractFoo {
    public void someMethod() {
        LOG.info("Using abstract log");
    }
}

Sự lựa chọn thứ hai 

Sử dụng nhật ký riêng cho từng lớp, siêu và người đăng ký:

public abstract class AbstractFoo {
    private static Log LOG = LogFactory.getLog(AbstractFoo.class);

    ...
}

public class Foo extends AbstractFoo {
    private static Log LOG = LogFactory.getLog(Foo.class);        

    public void someMethod() {
        LOG.info("Using own log");
    }
}

Điều gì có ý nghĩa hơn và tại sao?


39
2017-08-28 13:41


gốc




Các câu trả lời:


Tôi sẽ không làm. Thay vào đó tôi sẽ làm cho nó sử dụng đúng lớp trong cả hai trường hợp.

public abstract class AbstractFoo {
    protected final Log log = LogFactory.getLog(getClass());

    ...
}

public class Foo extends AbstractFoo {
    public void someMethod() {
        log.info("Using abstract log");
    }
}

Nếu bạn không thực hiện nhiều thao tác ghi nhật ký (đó là một ý tưởng hay), bạn có thể sử dụng phương thức thay thế.

public abstract class AbstractFoo {
    protected Log log() { return LogFactory.getLog(getClass()); }

    ...
}

Nếu có một lớp mà gọi rất nhiều, bạn có thể ghi đè lên nó để cung cấp cho bạn một thể hiện được lưu trữ.


67
2017-08-28 13:44



Cho đến nay tôi đã nhìn thấy hai cách tiếp cận: logger tĩnh (như trong câu hỏi) và logger không tĩnh (như trong ví dụ của bạn). Không phải là giải pháp logger tĩnh tốt hơn (một ví dụ của logger cho tất cả các trường hợp)? - Piotr De
logger tĩnh là tốt hơn nếu chúng là như nhau cho tất cả các trường hợp. Trong trường hợp lớp trừu tượng, lớp của các cá thể không giống nhau. - Peter Lawrey
Tôi thích điều này, nó có vẻ giống như một cách tốt để kết hợp cả hai lựa chọn. Bạn kết thúc với một bản ghi duy nhất nhưng nó liên kết với lớp thích hợp. +1 - shuniar
@Emilio Tôi sẽ gọi log() một getter như tất cả nó hiện nó là có được một giá trị. Bạn sẽ sử dụng cái gì thay vì protected? - Peter Lawrey
@Emilio Sự cố khi sử dụng log như một trường là bạn phải thêm mã vào mỗi lớp con để sử dụng trình ghi nhật ký thích hợp. Mặc dù, bằng cách sử dụng một trường là hiệu quả hơn nhiều cho mỗi cuộc gọi đặc biệt nếu bạn không thực sự đăng nhập, tức là ghi nhật ký bị tắt. - Peter Lawrey


Đây là giải pháp của tôi (logger tĩnh cuối cùng):

public abstract class AbstractFoo {
     protected Log getLogger();
     public doSomething() {
          getLogger().info("log something");
     }
}

public class Foo extends AbstractFoo {
    private static final Log log = Log.getLogger(Foo.class);

    protected Log getLogger() {
         return log;
    }
    public doSomethingElse() {
          log.info("log somethingElse");
    }
}

7
2018-04-08 08:20





Cả hai đều có ý nghĩa. Nó phụ thuộc vào ứng dụng của bạn.

Tôi nghĩ rằng thực hành thường xuyên hơn được sử dụng là có logger riêng cho mỗi lớp. Điều này cho phép bạn định cấu hình ghi nhật ký cho cả lớp và mỗi gói. Nhớ lấy AbstractFoo và Foo có thể thuộc về các gói khác nhau và có thể bạn muốn xem nhật ký từ Foo chỉ có.

Hơn nữa, hãy luôn nghĩ hai lần nếu bạn muốn viết protected cánh đồng. Nó không phải là hoàn toàn bị cấm nhưng một thực hành xấu nổi tiếng. Nó làm cho mã của bạn ít dễ đọc hơn và khó bảo trì.


4
2017-08-28 13:48





Nếu bạn tạo logger trong lớp trừu tượng, tất cả các bản ghi sẽ xuất hiện được gắn thẻ có nguồn gốc từ AbstractFoo. Nếu bạn muốn / cần xem nhật ký được gắn thẻ với lớp con mà từ đó nhật ký xảy ra, hãy tạo nhật ký cho các lớp con.


1
2017-08-28 13:51



"Nếu bạn tạo logger trong lớp trừu tượng, tất cả các bản ghi sẽ xuất hiện được gắn thẻ có nguồn gốc từ AbstractFoo" -> Không, không đúng nếu bạn sử dụng Câu trả lời được chấp nhận bởi @Peter_Lawrey. Sau đó, bạn nhận được các bản ghi được gắn thẻ với lớp làm việc ghi nhật ký, luôn luôn. - cellepo
'Vấn đề' với câu trả lời của Lawrey là bây giờ chúng là các logger dựa trên cá thể, không phải là ý tưởng. - MeBigFatGuy
@MeBigFatGuy Là nó xấu để có thể hiện dựa trên loggers? - valijon
Vâng, bạn đang lãng phí bộ nhớ và thời gian phân bổ những thứ này, và tạo ra nhiều rác hơn không có lý do. Chắc chắn có nhiều vấn đề ghê gớm hơn trong cuộc sống bên cạnh điều này, nhưng nó thật ngu ngốc. - MeBigFatGuy


Điều tương tự cũng có thể đạt được bằng cách chơi với các nhà xây dựng. Thêm nhật ký tại Căn cứ cấp lớp và đặt nó từ mọi Nguồn gốc lớp bằng cách sử dụng super (). Có mã:

public abstract class AbstractFoo {

    protected Log log;  // base abstract class has a Log object.

    public AbstractFoo(Log logger) {   // parameterized constructor for logger, to be used by the derived class.
        this.log = logger;
    }

    public doSomething() {        // common method for all the derived classes.
      log.info("log something");
    }
    // rest of business logic.
}

public class Foo extends AbstractFoo {

    public Foo(){
        super(LogFactory.getLog(AbstractFoo.class));
    }

    public void someMethod() {
        log.info("Using own log");     // this uses its own logger.
    }
}

1
2018-06-28 05:05