Details
-
Type:
Bug
-
Status:
Open
-
Priority:
Trivial
-
Resolution: Unresolved
-
Affects Version/s: UDIG 1.3.1
-
Fix Version/s: None
-
Component/s: framework
-
Labels:None
Description
The following has been reported via email:
log4j:WARN No appenders could be found for logger (org.geotools.factory).
log4j:WARN Please initialize the log4j system properly.
This is part of a general problem of a number of warning messages being issued as various open source projects start up.
The following clarification was offered on the user list:
Hi Donovan,
This is related to the way that log4j uses reflection to find the appender.
I haven't looked deeply within the new udig 1.3.0 code base yet so I am not sure where things have moved and indeed if there is a log appender, but I did notice that there is a bundled org.apache.log4 library.
I have been running with SLF and log4j logging in my RCP plugins for some time and there are a couple of things that need to be done to permit log4j to work from plugins, please view the notes below:
1. The bundled org.apache.log4j library provided in the udig code base doesn't have the correct directive in it to enable log4j to work, you need an Eclipse-BuddyPolicy: registered directive in the manifest of org.apache.log4j as follows:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.apache.log4j Bundle-SymbolicName: org.apache.log4j Bundle-Version: 9.0.1.20110423 Bundle-Vendor: Apache Log4j Export-Package: org.apache.log4j, org.apache.log4j.chainsaw, org.apache.log4j.config, org.apache.log4j.helpers, org.apache.log4j.jdbc, org.apache.log4j.jmx, org.apache.log4j.lf5, org.apache.log4j.lf5.config, org.apache.log4j.lf5.util, org.apache.log4j.lf5.viewer, org.apache.log4j.lf5.viewer.categoryexplorer, org.apache.log4j.lf5.viewer.configure, org.apache.log4j.lf5.viewer.images, org.apache.log4j.net, org.apache.log4j.nt, org.apache.log4j.or, org.apache.log4j.or.jms, org.apache.log4j.or.sax, org.apache.log4j.spi, org.apache.log4j.varia, org.apache.log4j.xml Eclipse-BuddyPolicy: registered Bundle-RequiredExecutionEnvironment: JavaSE-1.6
2. You will need to place a PluginLogAppender class in one or more plugins - see http://www.eclipsezone.com/eclipse/forums/t55300.html. The example I use follows:
/******************************************************************************* * Copyright (c) 2005 John J. Franey * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package IR_GIS; import java.text.MessageFormat; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.Level; import org.apache.log4j.spi.LoggingEvent; import org.eclipse.core.runtime.ILog; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.osgi.framework.Bundle; /** * log4j appender to an eclipse plugin's Ilog. * @author John J. Franey * */ public class PluginLogAppender extends AppenderSkeleton { private String symbolicName; /* (non-Javadoc) * @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent) */ protected void append(LoggingEvent event) { // don't go any further if event is not severe enough. if(! isAsSevereAsThreshold(event.getLevel())) return; ILog log = getBundleILog(); if(log == null) return; // if throwable information is available, extract it. Throwable t = null; if(event.getThrowableInformation() != null && layout.ignoresThrowable()) t = event.getThrowableInformation().getThrowable(); // build an Eclipse Status record, map severity and code from Event. Status s = new Status(getSeverity(event), getSymbolicName(), getCode(event), layout.format(event), t); log.log(s); } /** * map LoggingEvent's level to Status severity * @param ev * @return */ private int getSeverity(LoggingEvent ev) { Level level = ev.getLevel(); if(level == Level.FATAL || level == Level.ERROR) return IStatus.ERROR; else if(level == Level.WARN) return IStatus.WARNING; else if(level == Level.INFO) return IStatus.INFO; else // debug, trace and custom levels return IStatus.OK; } /** * Return the pluginId under which the messages will be logged * @return */ public String getSymbolicName() { return this.symbolicName; } public void setSymbolicName(String name) { this.symbolicName = name; } /** * map LoggingEvent to Status code * @param ev * @return */ private int getCode(LoggingEvent ev) { return 0; } private ILog getBundleILog() { // get the bundle for a plug-in Bundle b = Platform.getBundle(getSymbolicName()); if(b == null) { String m = MessageFormat.format("Plugin: {0} not found in {1}.", //$NON-NLS-1$ new Object[] {getSymbolicName(), this.name}); this.errorHandler.error(m); return null; } return Platform.getLog(b); } public void close() { // nothing to close } public boolean requiresLayout() { return true; } }
Then you need to make that PluginLogAppender visible by reflection, using an: Eclipse-RegisterBuddy: org.apache.log4j directive within the plugin manifest e.g.:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: IR_GIS (TM) Innovative Real-time Geographic Information System Bundle-SymbolicName: IR_GIS;singleton:=true Bundle-Version: 1.2.18 Bundle-Activator: IR_GIS.IRGISPlugin Bundle-Vendor: Arising Technology Systems Pty Limited Require-Bundle: org.apache.log4j, ri.common, net.refractions.udig.project, net.refractions.udig.mapgraphic, net.refractions.udig.printing.model, net.refractions.udig.printing.ui, net.refractions.udig.tool.default, net.refractions.udig.tool.info, net.refractions.udig.ui, ri.checklogin;bundle-version="1.2.3";resolution:=optional, ri.udig.InfotoolOverride;bundle-version="1.2.4";resolution:=optional Import-Package: org.eclipse.ui.plugin, org.slf4j Eclipse-RegisterBuddy: org.apache.log4j Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: IR_GIS;version="1.2.5"
3. I have kept the PluginLogAppender in the scope of ONE Plugin and its activator mandraulically configures the log4j properties via this code:
// Obtain the properties file to start the appender // the appender will be instantiated in this address space using this ClassLoader IConfiguration config = ConfigurationFactory.getDefault(); String pathName = config.findPath("log4j.properties").toOSString(); //$NON-NLS-1$ System.err.println(String.format("Path=%s", pathName)); PropertyConfigurator.configure(pathName); // Now obtain a logger, again instantiated via this ClassLoader logger = LoggerFactory.getLogger(this.getClass());
(Note that ConfigurationFactory is proprietary code, you will need to use some other means to obtain the pathname to the log4k.properties file.)
I haven't spent any time using more than one plugin to contain the PluginLogAppender, nor tried to investigate whether the 1.3.0 udig code base actually contains one or more PluginLogAppender instances or equivalent classes, but my product has been running with one appender setup this way for over a year, perhaps this is something the development team can fix in the current udig code base?
Ralph Holland,
B Sc, Dip Ed, Dip Com Sc,
MIEEE, MACM, MACS (SNR) CP.
Managing Director
Arising Technology Systems Pty Limited