2011-12-13 25 views
5

Chúng tôi có một thư viện java cũ đơn giản được khởi tạo từ nhiều ứng dụng khác nhau. Trong trường hợp này, mỗi ứng dụng là một ứng dụng web mà tất cả đều sống trong cùng một thùng chứa tomcat.logger riêng biệt cho từng trường hợp của một thư viện

Mỗi ứng dụng đăng nhập vào tệp nhật ký của riêng mình, bằng cách sử dụng trình ghi nhật ký riêng của nó. Chúng tôi muốn các bản ghi được tạo ra bởi các thư viện, đó là thích hợp cho một ứng dụng cụ thể, cũng đi đến các ứng dụng đó tập tin đăng nhập riêng biệt.

Đối với điều này, một cách là để cho phép các ứng dụng để vượt qua trong logger của nó đến thư viện:

library = new library(Logger applicationsVeryOwnLogger); 

Và sau đó sử dụng logger đó, để đăng nhập tất cả các báo cáo trong thư viện. Tuy nhiên, điều này có nghĩa rằng logger bây giờ là một biến lớp trong thư viện, và mọi lớp trong thư viện cần tham chiếu tới thư viện để sử dụng trình ghi nhật ký phù hợp.

Có cách nào tốt hơn để thực hiện việc này không?

Trả lời

2

Chúng tôi có nhu cầu tương tự trong một trong các ứng dụng cũ hơn của chúng tôi. Giải pháp mà chúng tôi đưa ra là một ResourceManager có thể truy xuất tài nguyên (Logger, Config files etc) bằng (context) ClassLoader.

Thường thì mọi ứng dụng được triển khai dưới dạng EAR đều có ClassLoader riêng và thư viện có thể gọi ResourceManager.getLogger() để nhận Logger được kết hợp với Chủ đề/Ứng dụng hiện tại. Bằng cách đó bạn không cần phải vượt qua nó với mọi cuộc gọi phương thức trong thư viện (nó đòi hỏi bạn có thể thay đổi thư viện tho).

import java.util.*; 
import java.util.logging.*; 

public class ResourceManager 
{ 
    private static final Map<ClassLoader, Map<String, Object>> resources = 
     Collections.synchronizedMap(new WeakHashMap<ClassLoader, Map<String, Object>>()); 
    public static final String LOGGER = Logger.class.getName(); 

    static 
    { 
     // adjust for log4j or other frameworks 
     final Logger logger = Logger.getLogger("logging.default"); 
     logger.setLevel(Level.ALL); 
     logger.addHandler(new ConsoleHandler() 
     { 
      { 
       setOutputStream(System.out); 
       setLevel(Level.ALL); 
      } 
     }); 
     registerResource(null, LOGGER, logger); 
    } 

    private static ClassLoader getApplicationScope() 
    { 
     return Thread.currentThread().getContextClassLoader(); 
    } 

    public static void registerResource(final String name, final Object resource) 
    { 
     registerResource(getApplicationScope(), name, resource); 
    } 

    public static synchronized void registerResource(final ClassLoader scope, final String name, final Object resource) 
    { 
     Map<String, Object> hm = null; 
     hm = resources.get(scope); 
     if (hm == null) 
     { 
      hm = Collections.synchronizedMap(new HashMap<String, Object>()); 
      resources.put(scope, hm); 
     } 
     hm.put(name, resource); 
    } 

    public static Object getResource(final String name) 
    { 
     for(ClassLoader scope = getApplicationScope();;scope = scope.getParent()) 
     { 
      final Map<String, Object> hm = resources.get(scope); 
      if ((hm != null) && hm.containsKey(name)) 
      { 
       return hm.get(name); 
      } 
      if (scope == null) break; 
     } 
     return null; 
    } 

    public static void registerLogger(final Logger logger) 
    { 
     registerResource(LOGGER, logger); 
    } 

    public static Logger getLogger() 
    { 
     return (Logger)getResource(LOGGER); 
    }  
} 

Đăng ký Logger trong giai đoạn init của EJB/WebApp (cần phải đăng ký trước khi bất kỳ cuộc gọi đến getLogger):

Logger logger = Logger.getLogger([Application Logger Name]); 
ResourceManager.registerLogger(logger); 

Lấy Logger trong thư viện (phương pháp hữu ích):

private Logger getLogger() 
    { 
     return ResourceManager.getLogger();  
    } 

Thao tác này sẽ trả về trình ghi nhật ký cho ứng dụng (EAR) được liên kết với chuỗi hiện tại.

Không giới hạn đối với Logger, nó cũng hoạt động với các tài nguyên khác mà bạn muốn chia sẻ.

Hạn chế:

  • wont work nếu bạn đóng gói nhiều ứng dụng/EJB mỗi EAR triển khai

  • ResourceManager và thư viện Logging cần phải được trên cùng một hoặc một ClassLoader cao hơn so với thư viện và ứng dụng. Nếu có một tùy chọn để bó thì cách tiếp cận của Alexanders là sạch hơn. (chúng tôi sử dụng java.util.logging theo mặc định ở cấp độ máy chủ để cách tiếp cận của anh ấy không hoạt động)

+0

Là một lưu ý phụ, giải pháp này cũng có thể được sử dụng để chia sẻ tất cả các loại tài nguyên, không chỉ logger. – Stefan

+0

bạn có thể muốn dán các phần có liên quan của mã trong câu trả lời của bạn, trong trường hợp liên kết bị chết trong tương lai. – rouble

+0

Một điều khác cần lưu ý về phương pháp này là ResourceManager.registerLogger() phải được gọi trước khi thư viện được khởi tạo. Nếu không, các logger lớp sẽ được thiết lập bằng cách sử dụng bộ ghi log mặc định. Điều này có thể là một bộ ngắt giao dịch cho một số triển khai. – rouble

3

Bạn đã đánh dấu câu hỏi của mình bằng thẻ log4j, vì vậy, tôi cho rằng đó là những gì bạn đang sử dụng.

Tôi hy vọng thư viện của bạn đang sử dụng tên gói duy nhất.

Nếu đúng như vậy, bạn có thể thực sự chỉ cần thiết lập trình ghi nhật ký cho gói đó.

log4j.category.my.lib.package = INFO, libFileAppender 
log4j.rootLogger = INFO, rootFileAppender 

Làm như vậy sẽ đăng các tin nhắn từ thư viện của bạn để cả hai libFileAppenderrootFileAppender.

Nếu bạn không muốn tin nhắn từ thư viện của bạn xuất hiện trong rootFileAppender bạn có thể tắt chức năng mà logger additivity, như thế này:

log4j.category.my.lib.package = INFO, libFileAppender 
log4j.additivity.my.lib.package = false 
log4j.rootLogger = INFO, rootFileAppender 

Với điều này, bạn sẽ chỉ thấy thông báo trong libFileAppender

+0

Tôi không nghĩ rằng điều này đáp ứng các yêu cầu. Với mỗi bản ghi này từ thư viện có thể được chuyển đến một nơi. Tuy nhiên, chúng tôi cần mỗi bản ghi từ thư viện được tạo bởi một ứng dụng cụ thể để đi đến một nơi (đó là tệp nhật ký của ứng dụng). – rouble

+0

@prmatta. Đưa tệp này vào WEB-INF/classes và thiết lập appender dành riêng cho ứng dụng đó và mỗi ứng dụng sẽ ghi lại các cuộc gọi thư viện tới appender đó. Tôi không thấy nó không đáp ứng yêu cầu của bạn như thế nào. –

+0

Arnt Logger/Appenders cho log4j được quản lý ở cấp JVM? Và nếu bạn sử dụng cùng một tên cho tất cả các logger (mà bạn phải vì thư viện cần tên) thì bạn tiếp tục đăng ký cùng một logger. – Stefan

Các vấn đề liên quan