Eclipse plugin development: error logging in log4j

2019-06-20 15:54发布

问题:

I'm trying to make my logging from log4j to go to the Eclipse Error Log view in my plugin.

I've got two external bundles:

  • Bundle 1: created a Plugin Development project based on existing JARs, containing the log4j library.
  • Bundle 2: created an empty Plugin Development project. Added a log4j.properties to it and a new class "VirtualConsole", which extends "ConsoleAppender".

This is how my log4j.properties looks like:

# Set root logger level to debug and its only appender to default.
log4j.rootLogger=debug, default
# default is set to be a ConsoleAppender.
log4j.appender.default=VirtualConsole
# default uses PatternLayout.
log4j.appender.default.layout=org.apache.log4j.PatternLayout
log4j.appender.default.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

And this is how my VirtualConsole looks like:

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.statushandlers.StatusManager;

public class VirtualConsole extends ConsoleAppender {

    @Override
    public void append(LoggingEvent event) {
        int level = IStatus.INFO;
        if (event.getLevel().equals(Level.ERROR))
            level = IStatus.ERROR;
        IStatus status = new Status(level, "myplugin",
                                event.getMessage().toString());
        StatusManager.getManager().handle(status, StatusManager.LOG);

        //and the normal logging
        super.append(event);
    }
}

This works. I've got my first bundle included as a dependency in the other bundles and when I run my plugin from within Eclipse by "right click > run as > Eclipse Application", I can run my plugin and when I (purposedly) do something where I now it is logging, the logs appear where they should - in the Error Log view.

As soon as I export my plugin, run a clean and fresh install of Eclipse and install the plugin via the "install software" system, it doesn't work anymore... nothing appears anywhere. I cannot get it to work and I honestly can't see where I'm going wrong.

Anyone able to give me some pointers? Thanks.


Update So this is how everything looks like now:

Manifest.MF from the bundle "bundle.log4jProperties":

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Log4jProperties
Fragment-Host: bundle.slf4j
Bundle-SymbolicName: bundle.log4jProperties
Bundle-Version: 1.0.1
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.7.0",
    bundle.slf4j
Eclipse-RegisterBuddy: bundle.slf4j

log4j.properties file in the bundle "bundle.log4jProperties":

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1
log4j.logger.org.hibernate.type=ERROR

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=bundle.log4jProperties.ErrorLogAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

ErrorLogAppender.java in the bundle "bundle.log4jProperties" (in a package "bundle.log4jProperties" as well, in the src folder):

package bundle.log4jProperties;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;


public class ErrorLogAppender extends AppenderSkeleton {

    @Override
    public void close() {}

    @Override
    public boolean requiresLayout() {
            return false;
    }

    @Override
    protected void append(LoggingEvent event) {
            //get the platform log
            ILog log = Platform.getLog(Platform.getBundle
                    ("bundle.log4jProperties"));

            //create an IStatus status
            IStatus status = new Status(getLevel(event.getLevel()),
                    "myPlugin",
                    getCode(event), 
                    getMessage(event), 
                    getThrowable(event));

            //log the status
            log.log(status);
    }

    private int getLevel(Level level) {
            int severity;
            if (level.equals(Level.ALL) || 
                level.equals(Level.ERROR) || 
                level.equals(Level.FATAL))
                    severity = IStatus.ERROR;
            else if (level.equals(Level.WARN))
                    severity = IStatus.WARNING;
            else if (level.equals(Level.INFO))
                    severity = IStatus.INFO;
            else severity = IStatus.INFO;
            return severity;
    }

    private int getCode(LoggingEvent event) {
            return (int) event.getTimeStamp();
    }
    private String getMessage(LoggingEvent event) {
            return event.getMessage().toString();
    }
    private Throwable getThrowable(LoggingEvent event) {
            ThrowableInformation info = event.getThrowableInformation();
            if (info != null)
                    return info.getThrowable();
            else return null;
    }
}

Over to the bundle "bundle.slf4j", which contains 3 jar files: Manifest.MF:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Slf4j
Bundle-SymbolicName: bundle.slf4j
Bundle-Version: 1.0.1
Bundle-ClassPath: slf4j-api-1.7.5.jar,
 slf4j-log4j12-1.7.5.jar,
 log4j-1.2.17.jar
Bundle-Vendor: apache
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.util,
 org.apache.log4j.lf5.viewer,
 org.apache.log4j.lf5.viewer.categoryexplorer,
 org.apache.log4j.lf5.viewer.configure,
 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.pattern,
 org.apache.log4j.rewrite,
 org.apache.log4j.spi,
 org.apache.log4j.varia,
 org.apache.log4j.xml,
 org.slf4j,
 org.slf4j.helpers,
 org.slf4j.impl,
 org.slf4j.spi
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Eclipse-BuddyPolicy: registered

Still all working when running from inside Eclipse as an Eclipse application, but not working when deploying to an update site and installing from there. I reckon this might have to do with the properties file not being found, but what do I have to change if I want the file to be found??

Note: feature.xml, which I'm exporting to the updatesite, contains this as well (truncated and left out what's not necessary):

<requires>
    <import plugin="bundle.slf4j" version="1.0.1" match="greaterOrEqual"/>
</requires>

<plugin
    id="bundle.slf4j"
    download-size="0"
    install-size="0"
    version="0.0.0"/>

<plugin
    id="bundle.log4jProperties"
    download-size="0"
    install-size="0"
    version="0.0.0"
    fragment="true"
    unpack="false"/>

I couldn't add the bundle.log4jProperties to the required plugins as that gives me the warning that that plugin could not be resolved. Somehow I think this is related to my problem but how on earth am I supposed to make my feature.xml (in the bundle "feature", separate) "resolve" another bundle which is in the same workspace and working? Especially weird because that same feature.xml does revolve the plugin in the plugin-statement.

Please, anyone. Help. It's pretty fantastic that I'm struggling with something that's done in almost every plugin out there, but I can't manage to find a solution anywhere. Bottom line: I want to log errors to the error log view. That's gotta be possible, right?