Durante mucho tiempo he venido instalando aplicaciones en Tomcat y cada una de ellas tenía su propio archivo de configuración de log4j ubicado en algún lugar no muy preciso y con suerte dispar al momento de lograr generar logs.
Cierto día, harto de esta situación, me tomé el trabajo de investigar y dar con una solución definitiva a este problema.
Una forma normal de realizar la configuración de log4j para una aplicación web es ubicar el archivo log4j.properties en el directorio WEB-INF/classes de la webapp. Log4j encontrará el archivo y se iniciará correctamente.
En caso de querer usar un nombre de archivo diferente al usado por defecto (expresado en el párrafo de arriba), se puede configurar una variable de entorno de la siguiente manera:
TOMCAT_OPTS=”-Dlog4j.configuration=foobar.txt”
Dicho archivo debe estar tambien ubicado en WEB-INF/classes y será leído dentro de nuestra aplicación con PropertyConfigurator.
Hasta aquí todo es correcto en cuanto a que log4j encuentre al archivo de configuración para nuestra aplicación. Sin embargo, dado que cada aplicación tendrá su propio archivo de configuración, cada una de ellas cargará tambien sus propios class loaders al momento de inicializar el sistema y esto generará una situación peligrosa ya que no habrá ningun tipo de sincronización entre ellos.
Una forma correcta de salvar esta situación consiste en crear un listener que inicialize cada una de nuestras aplicaciones web y, al mismo tiempo, lograr tener un archivo de log para cada aplicación.
Ejemplo
Dentro de mi archivo log4j.properties defino un appender de la siguiente manera:
log4j.appender.logfile.File=${app.root}/notif.log
Con esto estoy indicando el nombre del archivo y estoy dejando el path del mismo abierto a ser inicializado. De esta forma, el día que deba mover mi aplicación a otro directorio/servidor, no deberé preocuparme de tocar esta configuración.
En este caso, ${app.root} será una propiedad del sistema.
Para inicializar ${app.root}, algunas personas suelen usar propiedades del sistema como catalina.base o catalina.home, que se encuentran en los scripts de inicio de Tomcat 5.x. Sin embargo, he descubierto que muchas veces ese método falla por lo que suelo aplicar el mío, el cual paso a detallar.
Como dije antes, hay que crear un listener para nuestra aplicación y allí creo una variable de sistema de la siguiente manera:
String prefixLogFile = sce.getServletContext().getRealPath("/WEB-INF"); System.setProperty("app.root", prefixLogFile);
Allí obtengo el path real de la aplicación y se lo paso a la variable que he creado. Por lo tanto, cuando Tomcat se inicie, ${app.root} será remplazada por el path real.
Ahora solo queda lograr que log4j encuentre y lea nuestro archivo de configuración y para ello, pondremos en nuestro listener lo siguiente:
public void contextInitialized( ServletContextEvent sce ) { // Init log4j configuration String prefix = sce.getServletContext().getRealPath("/"); PropertyConfigurator.configure(prefix+ "/WEB-INF/log4j.properties");
De esta forma forma hemos resuelto el problema y nuestra aplicación generará los logs mediante log4j sin deperdiciar recursos del sistema.
Nuestro listener final queda pues así:
public void contextInitialized( ServletContextEvent sce ) { String prefixLogFile = sce.getServletContext().getRealPath("/WEB-INF"); System.setProperty("app.root", prefixLogFile); String prefix = sce.getServletContext().getRealPath("/"); PropertyConfigurator.configure(prefix + "/WEB-INF/log4j.properties");
Y listo !!!