/* * Copyright 2006 Niclas Hedhman. * Copyright 2012 Guillaume Nodet. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.log4j; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import org.apache.log4j.config.PaxPropertySetter; import org.apache.log4j.config.PropertySetter; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.spi.AppenderAttachable; import org.apache.log4j.spi.ErrorHandler; import org.apache.log4j.spi.Filter; import org.apache.log4j.spi.LoggerRepository; import org.apache.log4j.spi.OptionHandler; import org.ops4j.pax.logging.service.internal.AppenderBridgeImpl; import org.ops4j.pax.logging.service.internal.ErrorHandlerBridgeImpl; import org.ops4j.pax.logging.service.internal.FilterBridgeImpl; import org.ops4j.pax.logging.service.internal.LayoutBridgeImpl; import org.ops4j.pax.logging.service.internal.PaxAppenderProxy; import org.osgi.framework.BundleContext; public class PaxLoggingConfigurator extends PropertyConfigurator { public static final String OSGI_PREFIX = "osgi:"; private static final String LOGGER_REF = "logger-ref"; private static final String ROOT_REF = "root-ref"; private static final String APPENDER_REF_TAG = "appender-ref"; private LoggerRepository repository; private BundleContext m_bundleContext; private List proxies = new ArrayList(); public PaxLoggingConfigurator( BundleContext bundleContext ) { m_bundleContext = bundleContext; } public List getProxies() { return proxies; } public void doConfigure(Properties properties, LoggerRepository hierarchy) { repository = hierarchy; super.doConfigure(properties, hierarchy); } Appender parseAppender( Properties props, String appenderName ) { Appender appender = registryGet( appenderName ); if( appender != null ) { LogLog.debug("Appender \"" + appenderName + "\" was already parsed."); return appender; } if( appenderName.startsWith(OSGI_PREFIX) ) { String osgiAppenderName = appenderName.substring(OSGI_PREFIX.length()); PaxAppenderProxy paxAppender = new PaxAppenderProxy( m_bundleContext, osgiAppenderName ); proxies.add(paxAppender); appender = new AppenderBridgeImpl( paxAppender ); appender.setName(appenderName); } else { // Appender was not previously initialized. String prefix = APPENDER_PREFIX + appenderName; String layoutPrefix = prefix + ".layout"; appender = (Appender) OptionConverter.instantiateByKey(props, prefix, org.apache.log4j.Appender.class, null); if (appender == null) { LogLog.error("Could not instantiate appender named \"" + appenderName + "\"."); return null; } appender.setName(appenderName); if (appender instanceof OptionHandler) { if (appender.requiresLayout()) { String layoutClass = OptionConverter.findAndSubst(layoutPrefix, props); if (layoutClass != null && layoutClass.startsWith(OSGI_PREFIX)) { String osgiLayoutName = layoutClass.substring(OSGI_PREFIX.length()); Layout fallback = null; String fallbackClass = OptionConverter.findAndSubst(layoutPrefix + ".fallback", props); if (fallbackClass != null) { fallback = (Layout) OptionConverter.instantiateByKey( props, layoutPrefix + ".fallback", Layout.class, null); if (fallback != null) { PaxPropertySetter.setProperties(fallback, props, layoutPrefix + ".fallback."); } } Layout layout = new LayoutBridgeImpl( m_bundleContext, osgiLayoutName, fallback ); appender.setLayout(layout); } else { Layout layout = (Layout) OptionConverter.instantiateByKey(props, layoutPrefix, Layout.class, null); if (layout != null) { appender.setLayout(layout); LogLog.debug("Parsing layout options for \"" + appenderName + "\"."); //configureOptionHandler(layout, layoutPrefix + ".", props); PaxPropertySetter.setProperties(layout, props, layoutPrefix + "."); LogLog.debug("End of parsing for \"" + appenderName + "\"."); } } } final String errorHandlerPrefix = prefix + ".errorhandler"; String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props); if (errorHandlerClass != null && errorHandlerClass.startsWith(OSGI_PREFIX)) { String errorHandlerName = errorHandlerClass.substring(OSGI_PREFIX.length()); ErrorHandler fallback = (ErrorHandler) OptionConverter.instantiateByKey(props, errorHandlerPrefix + ".fallback", ErrorHandler.class, null); if (fallback != null) { parseErrorHandler(fallback, errorHandlerPrefix + ".fallback", props, repository); } ErrorHandler eh = new ErrorHandlerBridgeImpl( m_bundleContext, errorHandlerName, fallback ); appender.setErrorHandler(eh); } else if (errorHandlerClass != null) { ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByKey(props, errorHandlerPrefix, ErrorHandler.class, null); if (eh != null) { appender.setErrorHandler(eh); LogLog.debug("Parsing errorhandler options for \"" + appenderName + "\"."); LogLog.debug("End of errorhandler parsing for \"" + appenderName + "\"."); } } if (appender instanceof AppenderAttachable) { final String appenderPrefix = prefix + ".appenders"; String appenderNames = OptionConverter.findAndSubst(appenderPrefix, props); StringTokenizer st = new StringTokenizer(appenderNames, ","); Appender childAppender; String childAppenderName; while(st.hasMoreTokens()) { childAppenderName = st.nextToken().trim(); if( childAppenderName == null || childAppenderName.equals(",") ) { continue; } LogLog.debug("Parsing appender named \"" + childAppenderName +"\"."); childAppender = parseAppender(props, childAppenderName); if( childAppender != null ) { ((AppenderAttachable) appender).addAppender(childAppender); } } } //configureOptionHandler((OptionHandler) appender, prefix + ".", props); PaxPropertySetter.setProperties(appender, props, prefix + "."); LogLog.debug("Parsed \"" + appenderName + "\" options."); } } parseAppenderFilters(props, appenderName, appender); registryPut(appender); return appender; } private void parseErrorHandler( final ErrorHandler eh, final String errorHandlerPrefix, final Properties props, final LoggerRepository hierarchy) { boolean rootRef = OptionConverter.toBoolean( OptionConverter.findAndSubst(errorHandlerPrefix + ROOT_REF, props), false); if (rootRef) { eh.setLogger(hierarchy.getRootLogger()); } String loggerName = OptionConverter.findAndSubst(errorHandlerPrefix + LOGGER_REF, props); if (loggerName != null) { Logger logger = (loggerFactory == null) ? hierarchy.getLogger(loggerName) : hierarchy.getLogger(loggerName, loggerFactory); eh.setLogger(logger); } String appenderName = OptionConverter.findAndSubst(errorHandlerPrefix + APPENDER_REF_TAG, props); if (appenderName != null) { Appender backup = parseAppender(props, appenderName); if (backup != null) { eh.setBackupAppender(backup); } } final Properties edited = new Properties(); final String[] keys = new String[] { errorHandlerPrefix + "." + ROOT_REF, errorHandlerPrefix + "." + LOGGER_REF, errorHandlerPrefix + "." + APPENDER_REF_TAG }; for(Iterator iter = props.entrySet().iterator();iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); int i = 0; for(; i < keys.length; i++) { if(keys[i].equals(entry.getKey())) break; } if (i == keys.length) { edited.put(entry.getKey(), entry.getValue()); } } PaxPropertySetter.setProperties(eh, edited, errorHandlerPrefix + "."); } void parseAppenderFilters(Properties props, String appenderName, Appender appender) { // extract filters and filter options from props into a hashtable mapping // the property name defining the filter class to a list of pre-parsed // name-value pairs associated to that filter final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter."; int fIdx = filterPrefix.length(); Hashtable filters = new Hashtable(); Enumeration e = props.keys(); String name = ""; while (e.hasMoreElements()) { String key = (String) e.nextElement(); if (key.startsWith(filterPrefix)) { int dotIdx = key.indexOf('.', fIdx); String filterKey = key; if (dotIdx != -1) { filterKey = key.substring(0, dotIdx); name = key.substring(dotIdx+1); } Vector filterOpts = (Vector) filters.get(filterKey); if (filterOpts == null) { filterOpts = new Vector(); filters.put(filterKey, filterOpts); } if (dotIdx != -1) { String value = OptionConverter.findAndSubst(key, props); filterOpts.add(new NameValue(name, value)); } } } // sort filters by IDs, insantiate filters, set filter options, // add filters to the appender Enumeration g = new SortedKeyEnumeration(filters); while (g.hasMoreElements()) { String key = (String) g.nextElement(); String clazz = props.getProperty(key); if (clazz.startsWith(OSGI_PREFIX)) { String filterName = clazz.substring(OSGI_PREFIX.length()); Filter fallback = null; String fallbackClass = OptionConverter.findAndSubst(key + ".fallback", props); if (fallbackClass != null) { fallback = (Filter) OptionConverter.instantiateByKey(props, key + ".fallback", Filter.class, null); if (fallback != null) { PaxPropertySetter.setProperties(fallback, props, key + ".fallback."); } } Filter filter = new FilterBridgeImpl( m_bundleContext, filterName, fallback ); appender.addFilter(filter); } else if (clazz != null) { LogLog.debug("Filter key: ["+key+"] class: ["+props.getProperty(key) +"] props: "+filters.get(key)); Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, Filter.class, null); if (filter != null) { PropertySetter propSetter = new PropertySetter(filter); Vector v = (Vector)filters.get(key); Enumeration filterProps = v.elements(); while (filterProps.hasMoreElements()) { NameValue kv = (NameValue)filterProps.nextElement(); propSetter.setProperty(kv.key, kv.value); } propSetter.activate(); LogLog.debug("Adding filter of type ["+filter.getClass() +"] to appender named ["+appender.getName()+"]."); appender.addFilter(filter); } } else { LogLog.warn("Missing class definition for filter: ["+key+"]"); } } } }