2011-12-13 7 views
5

Tenemos una biblioteca java antigua simple que se crea una instancia de muchas aplicaciones diferentes. En este caso, cada aplicación es una aplicación web que todos viven en el mismo contenedor de tomcat.registrador separado para cada instancia de una biblioteca

Cada aplicación inicia sesión en su propio archivo de registro, utilizando su propio registrador. Queremos que los registros generados por la biblioteca, que son pertinentes para una aplicación específica, también vayan a las aplicaciones separadas del archivo de registro.

Para ello, una forma es para permitir que la aplicación pase en su registrador a la biblioteca:

library = new library(Logger applicationsVeryOwnLogger); 

Y luego usar ese registrador, para registrar todas las declaraciones en la biblioteca. Sin embargo, esto significa que el registrador ahora es una variable de clase en la biblioteca, y cada clase en la biblioteca necesita una referencia a la biblioteca para usar el registrador correcto.

¿Hay mejores formas de hacerlo?

Respuesta

2

Tuvimos una necesidad similar en una de nuestras aplicaciones anteriores. La solución que obtuvimos fue un ResourceManager que recuperaría recursos (Logger, Config files, etc.) por (context) ClassLoader.

Por lo general, cada aplicación implementada como un EAR obtiene su propio ClassLoader y la biblioteca puede simplemente llamar a ResourceManager.getLogger() para obtener el registrador asociado con el subproceso/aplicación actual. De esta forma, no necesita pasarlo con cada llamada a un método en la biblioteca (requiere que usted pueda cambiar la biblioteca).

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

Registro Logger en la fase de inicio de EJB/aplicación web (tiene que ser registrada antes de cualquier llamada a getLogger):

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

Recuperar Logger en la biblioteca (método de utilidad):

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

Esto devolverá el registrador para la aplicación (EAR) que está asociada con el hilo actual.

No limitado a los registradores, también funciona para otros recursos que desee compartir.

Limitaciones:

  • no funcionará si empaquetar múltiples aplicaciones/EJB por EAR desplegado

  • ResourceManager y la biblioteca de registro deben estar incluidos en el mismo o un cargador de clases más alta que la biblioteca y aplicación. Si hay una opción para agrupar, el enfoque de Alexanders es más limpio. (usamos java.util.logging que es por defecto en el nivel del servidor por lo que su enfoque no funciona)

+0

Como nota al margen, esta solución también se puede usar para compartir todo tipo de recursos, no solo los registradores. – Stefan

+0

es posible que desee pegar secciones de código relevantes en su respuesta, en caso de que el enlace muera en el futuro. – rouble

+0

Otra cosa a tener en cuenta acerca de este método es que se debe invocar a ResourceManager.registerLogger() antes de crear una instancia de la biblioteca. De lo contrario, los registradores de clase se establecerán utilizando el registrador predeterminado. Esto puede ser un factor decisivo para algunas implementaciones. – rouble

3

Marcó su pregunta con la etiqueta log4j, así que supongo que eso es lo que está usando.

Espero que su biblioteca utilice un nombre de paquete único.

Si ese es el caso, puede simplemente configurar un registrador para ese paquete.

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

Si lo hace, los mensajes de registro de su biblioteca a la vez libFileAppender y rootFileAppender.

Si usted no quiere a los mensajes de la biblioteca a aparecer en rootFileAppender puede apagar esa aditividad registrador, así:

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

Con esto, sólo verá el mensaje en libFileAppender

+0

No creo que esto cumpla con los requisitos. Con esto, cada registro de la biblioteca se puede redirigir a un lugar. Sin embargo, necesitamos que cada registro de la biblioteca generado por una aplicación específica vaya a un lugar (que es el archivo de registro de la aplicación). – rouble

+0

@prmatta. Tire este archivo a WEB-INF/classes y configure el appender que sea específico para esa aplicación y cada aplicación registrará las llamadas de la biblioteca a ese appender. No veo cómo no cumple con sus requisitos. –

+0

¿Arnt los Loggers/Appenders para log4j manejado en un nivel de JVM? Y si usa el mismo nombre para todos los registradores (lo cual debe hacer porque la biblioteca necesita el nombre), entonces sigue registrando el mismo registrador. – Stefan

Cuestiones relacionadas