2012-08-28 39 views
35

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

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

Sử dụng đơn log từ siêu lớp cho lớp đó và mọi tầng lớp phụ:

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"); 
    } 
} 

Second Lựa chọn

Sử dụng nhật ký riêng cho mỗi 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?

Trả lời

58

Tôi cũng 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ý (bạn nên sử dụng phương pháp thay thế).

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

    ... 
} 

Nếu có một lớp gọi quá nhiều bạn có thể ghi đè lên để cung cấp cho bạn một bản sao được lưu trong bộ nhớ cache.

+1

Cho đến nay tôi đã thấy hai phương pháp: logger tĩnh (như 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)? –

+4

logger tĩnh tốt hơn nếu chúng giống 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. –

+0

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

2

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

Tôi nghĩ rằng thực tế thường được sử dụng hơn là có trình ghi nhật ký riêng cho từng 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. Hãy nhớ rằng, AbstractFooFoo có thể thuộc các gói khác nhau và có thể bạn chỉ muốn xem nhật ký từ Foo.

Hơn nữa, hãy luôn nghĩ hai lần nếu bạn muốn viết trường protected. 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ì.

1

Nếu bạn tạo trình ghi nhật ký trong lớp trừu tượng, tất cả nhật ký 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.

+0

"Nếu bạn tạo trình ghi nhật ký trong lớp trừu tượng, tất cả các nhật ký sẽ xuất hiện được gắn thẻ là 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

+0

'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

5

Đây là giải pháp của tôi (chính thức logger tĩnh):

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"); 
    } 
} 
1

Cùng có thể đạt được bằng cách chơi với nhà thầu. Thêm nhật ký tại số Cơ sở cấp lớp và đặt nó từ mọi lớp Có nguồn gốc lớp bằng cách sử dụng siêu(). 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. 
    } 
} 
Các vấn đề liên quan