2011-12-13 15 views
5

Birçok farklı uygulamadan elde edilen eski bir java kitaplığımız var. Bu durumda, her uygulama aynı tomcat konteynerinde yaşayan bir web uygulamasıdır. Her uygulama kendi logger'ını kullanarak kendi günlük dosyasına kaydedilir. Kütüphane tarafından oluşturulan ve belirli bir uygulamaya uygun olan günlükleri de bu uygulamaların ayrı bir günlük dosyasına gitmesini istiyoruz.Bir kütüphanenin her bir örneği için ayrı bir günlük kaydedici

library = new library(Logger applicationsVeryOwnLogger); 

Ve sonra kütüphanedeki tüm ifadeleri günlüğe o logger kullanımı: Bunun için

, tek yönlü uygulama kütüphanesine kendi tarihçesinde geçmesine olanak sağlamaktır. Bununla birlikte, bu, günlüğün artık kitaplıktaki bir sınıf değişkeni olduğu ve kitaplıktaki her sınıfın doğru kaydediciyi kullanmak için kitaplığa başvurması gerektiği anlamına gelir.

Bunu yapmanın daha iyi yolları var mı?

cevap

2

Eski uygulamalarımızdan birinde benzer bir ihtiyacımız vardı. Geldiğimiz çözüm, (içerik) ClassLoader tarafından kaynakları (Logger, Config dosyaları vb.) Alabilecek bir ResourceManager'tı.

Genellikle EAR tarafından dağıtılan her uygulama kendi ClassLoader'ını alır ve kitaplık o anda geçerli Thread/Application ile ilişkili Logger'ı almak için ResourceManager.getLogger() öğesini çağırır. Bu şekilde kütüphanede her yöntem çağrısıyla iletmenize gerek yoktur (kütüphaneyi değiştirmenizi gerektirir).

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

kütüphanede Kaydediciyi al (yardımcı yöntemi):

private Logger getLogger() 
    { 
     return ResourceManager.getLogger();  
    } 
EJB/WebApp init fazında

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

Kayıt Kaydedici (getLogger için herhangi bir çağrı önce kayıtlı olması gerekir)

Bu, geçerli iş parçacığıyla ilişkili uygulama için kaydediciyi (EAR) döndürecektir.

Logger'larla sınırlı değil, paylaşmak istediğiniz diğer kaynaklar için de çalışıyor.

Sınırlamalar: Eğer dağıtılan EAR

  • ResourceManager ve Günlük kütüphaneye başına birden fazla uygulama/EJB'ler paket halinde

    • alışkanlık iş aynı veya kütüphane ve uygulama daha yüksek ClassLoader üzerinde olması gerekiyor. Paketleme seçeneği varsa, Alexanders yaklaşımı daha temizdir. (varsayılan olarak sunucu seviyesinde olan java.util.logging'i kullanır, böylece yaklaşımı işe yaramaz)

  • +0

    Bir yan not olarak, bu çözüm, sadece kaydedicilere değil, her türlü kaynağı paylaşmak için de kullanılabilir. – Stefan

    +0

    linkin gelecekte ölmesi durumunda, cevabınıza ilgili kod bölümlerini yapıştırmak isteyebilirsiniz. – rouble

    +0

    Bu yöntem hakkında dikkat edilmesi gereken diğer bir nokta, kitaplığın başlatılmasından önce ResourceManager.registerLogger() öğesinin çağrılması gerektiğidir. Aksi takdirde, sınıf kaydedicileri varsayılan kayıt cihazı kullanılarak ayarlanacaktır. Bu, bazı uygulamalar için bir anlaşma olabilir. – rouble

    3

    Sorunuzu log4j etiketiyle işaretlediniz, bu yüzden kullandığınız şeyin olduğunu farz ediyorum.

    Umarım kütüphaneniz benzersiz bir paket adı kullanıyordur.

    Bu durumda, yalnızca bu paket için bir günlük kaydedici kurabilirsiniz.

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

    hem libFileAppender ve rootFileAppender için kitaplıktan günlük mesajları görecektir.

    böyle, o logger toplanırlığını kapatabilir sen rootFileAppender görünmeleri için kütüphaneden iletilere istemiyorsanız: Bununla

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

    , sadece libFileAppender mesajı göreceksiniz

    +0

    Bunun gereksinimleri karşıladığını düşünmüyorum. Bununla kütüphaneden her günlüğü tek bir yere yönlendirilebilir. Ancak, belirli bir uygulama tarafından oluşturulan kütüphaneden her günlüğe bir yere (uygulamanın günlük dosyası olan) gitmesi gerekir. – rouble

    +0

    @prmatta. Bu dosyayı WEB-INF/sınıflarına ve bu uygulamaya özgü bir uygulama ekleyicisine atın ve her bir uygulama kütüphaneyi bu ekleyiciye çağırır. Gereksinimlerinizi karşılamadığını göremiyorum. –

    +0

    Log4j için Kaydediciler/Ekleyiciler JVM düzeyinde yönetiliyor mu? Ve eğer tüm logger'lar için aynı ismi kullanırsanız (ki bu kütüphane ismi gerektirdiği için), aynı kayıt cihazını kaydetmeye devam edersiniz. – Stefan

    İlgili konular