Logging from Static Methods in e4

My Issue

The e4 programming model relies on a XML application model and dependency injection.
When a model element is created, fields are injected by the framework. This injection relies on a context. There is not one context, but a hierarchy of contexts, one being marked as active.

In my application, I have some utility methods which are static.
So, they are not part of my application model. Sometimes, they trigger exceptions that can be silenced. They do not block the user. However, I would like to let a trace so that I can know there was a problem. Just in case… So, instead of completely silencing these exceptions, I would like to log them with the “debug” level.

Here is an example skeleton:

public static String doSomething( String someParameter ) {

	try {
		// Do something

	} catch( Exception e ) {
		// Log a non-critical exception
	}

	return "some result";
}

Usually, with e4, you would proceed as follows to inject a logger.

@Inject
org.eclipse.e4.core.services.log.Logger logger;

But since my utilities are not part of the application model, there will be no injection.

What I Tried

First, I noticed the e4 logger was in discouraged access.
So, rather than having useless warnings everywhere in my code, I decided to centralize my invocations through a single filtering class that would handle logging for my entire plugin. This way, I bring my injection issue back into a single class.

public class MyLogManager {

	@Inject
	Logger logger;

	/** As an example... */
	public void log( String msg ) {
		logger.info( msg );
	}
}

There is a way to inject fields in a custom object, by using the contexts.
The big deal is to find the right context. The easiest one is to get the bundle one. Remember fields are injected after the object creation. You cannot inject fields in a class in its constructor.

public static MyLogManager createLogger() {
	Bundle bundle = FrameworkUtil.getBundle( MyLogManager.class );
	IEclipseContext context = EclipseContextFactory.getServiceContext( bundle.getBundleContext());
	MyLogManager myObject = ContextInjectionFactory.make( MyLogManager.class, context );
	return myObject;
}

Except I get an exception.
No logger was found in the bundle context.

Caused by: org.eclipse.e4.core.di.InjectionException: Unable to process “MyLogManager.logger”: no actual value was found for the argument “Logger”.

It does not work better with the context of e4’s workbench.

IEclipseContext context = E4Workbench.getServiceContext();
MyLogManager myObject = ContextInjectionFactory.make( MyLogManager.class, context );

And, as a reminder, no problem with injecting a logger within an application model element.
So, the issue is really finding the right context.

How I Solved It

By looking at the code and the implementation of the logger service, I finally found a workaround.
There is not enough information in my bundle context to inject the logger. But I have enough information to instantiate a new one with this context. The implementation I use is the default one in the workbench, WorkbenchLogger.

public class MyLogManager {

	public static final MyLogManager INSTANCE = new MyLogManager();
	private Logger logger;

	/**
	 * Constructor.
	 */
	private MyLogManager() {
		Bundle bundle = FrameworkUtil.getBundle( LogManager.class );
		IEclipseContext context = EclipseContextFactory.getServiceContext( bundle.getBundleContext());
		this.logger = ContextInjectionFactory.make( WorkbenchLogger.class, context );
	}

	/** As an example... */
	public void log( String msg ) {
		logger.info( msg );
	}
}

There may be a cleaner solution.
But until I find it, this one works.

One thought on “Logging from Static Methods in e4

  1. I had the exact same experience. Strange that logging is under “discouraged access”. I would assume that to be a valid public API.

Leave a comment