/* * Copyright (C) 2005-2007 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have recieved a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.repo.admin; import java.io.BufferedInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Properties; import org.apache.log4j.jmx.HierarchyDynamicMBean; import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.spi.LoggerRepository; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; /** * Initialises Log4j's HierarchyDynamicMBean (refer to core-services-context.xml) * and any overriding log4.properties files. * <p> * Alfresco modules can provide their own log4j.properties file, * which augments/overrides the global log4j.properties within * the Alfresco webapp. Within the module's source tree, suppose * you create:<pre> * config/alfresco/module/{module.id}/log4j.properties</pre> * At deployment time, this log4j.properties file will be placed in:<pre> * WEB-INF/classes/alfresco/module/{module.id}/log4j.properties</pre> * Where {module.id} is whatever value is set within the AMP's * module.properties file. For details, see: * <a href='http://wiki.alfresco.com/wiki/Developing_an_Alfresco_Module'>Developing an Alfresco Module</a> * <p> * For example, if {module.id} is "org.alfresco.module.avmCompare", then * within your source code you'll have:<pre> * config/alfresco/module/org.alfresco.module.avmCompare/log4j.properties</pre> * This would be deployed to:<pre> * WEB-INF/classes/alfresco/module/org.alfresco.module.avmCompare/log4j.properties</pre> * By default the 'overriding_log4j_properties' property of the * 'log4JHierarchyInit' bean within core-services-context.xml is:<pre> * classpath*:alfresco/module/*/log4j.properties</pre> * Therefore, Log4JHierarchyInit will discover this supplimentary log4j.properties * file, and merge it with the main log4j.file (WEB-INF/classes/log4j.properties). * For example, the org.alfresco.module.avmCompare log4j.properties file might look like this: * <pre> * #----------------------------------------------------------------------- * # webscript module log4j.properties * # * # NOTE * # ---- * # * # Log4j uses the following logging levels: * # debug,info,warn,error,fatal * # * # To set the logging level of {fullClassName} to {loglevel}, * # add a line to this file of the following form: * # * # log4j.logger.{fullClassName}={loglevel} * # * # For example, to make 'com.example.MyExample' produce 'debug' * # logs, add a line like this: * # * # log4j.logger.com.example.MyExample=debug * # * # * # WARNING * # ------- * # Log properties in this log4j.properties file override/augment * # those in the webapp's main log4j.properties. * # * #----------------------------------------------------------------------- * * log4j.logger.org.alfresco.module.avmCompare.AvmCompare=info * </pre> * * This system allows the author of any module to provide rich logging control * without concern for corrupting the central log4j.properties file during * AMP installation/deinstallation. For details, see: * <a href='http://wiki.alfresco.com/wiki/Module_Management_Tool'>Module Management Tool</a> */ public class Log4JHierarchyInit { private HierarchyDynamicMBean log4jHierarchy; private List<String> extra_log4j_urls; public Log4JHierarchyInit() { extra_log4j_urls = new ArrayList<String>(); } /** * Loads a set of augmenting/overriding log4j.properties files * from locations specified via an array of 'spring_urls' * (typically provided by a core-services-context.xml). * * This function supports Spring's syntax for retrieving * multiple class path resources with the same name, * via the "classpath*:" prefix. For details, see: * <a href='http://www.jdocs.com/spring/1.2.8/org/springframework/core/io/support/PathMatchingResourcePatternResolver.html'>PathMatchingResourcePatternResolver</a>. */ public void setOverriding_log4j_properties(List<String> spring_urls) { for ( String url : spring_urls ) { extra_log4j_urls.add( url ); } } public void setLog4jHierarchy(HierarchyDynamicMBean log4jHierarchy) { this.log4jHierarchy = log4jHierarchy; } @SuppressWarnings("unchecked") public void init() { // Add each logger (that has a level set) from // the Log4J Repository to the Hierarchy MBean LoggerRepository r = LogManager.getLoggerRepository(); // Include overriding loggers // // Typically, extra loggers come from AMP modules, but you // could add others by augmenting core-services-context.xml // This mechanism allows modules to have their own local // log4j.properties file within: // // WEB-INF/classes/alfresco/module/{module.id}/log4j.properties // // Where: module.id is whatever value is set within the AMP's // 'module.properties' file. // // See also: // http://wiki.alfresco.com/wiki/Developing_an_Alfresco_Module // (the module.properties section) // // And: // core-services-context.xml set_overriding_loggers( r ); Enumeration loggers = r.getCurrentLoggers(); Logger logger = null; while (loggers.hasMoreElements()) { logger = (Logger)loggers.nextElement(); if (logger.getLevel() != null) { log4jHierarchy.addLoggerMBean(logger.getName()); } } } void set_overriding_loggers( LoggerRepository hierarchy ) { for ( String spring_url : extra_log4j_urls ) { set_overriding_logger( spring_url, hierarchy ); } } void set_overriding_logger( String spring_url, LoggerRepository hierarchy ) { PathMatchingResourcePatternResolver resolver; PropertyConfigurator prop_config; prop_config = new PropertyConfigurator(); resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = null; try { resources = resolver.getResources( spring_url ); } catch (Exception e) { return ; } // Read each resource for (Resource resource : resources ) { try { InputStream istream = new BufferedInputStream(resource.getInputStream()); Properties properties = new Properties(); properties.load(istream); prop_config.doConfigure(properties, hierarchy); } catch (Throwable e) { /* do nothing */ } } } }