# Log4J und RCP (ConsoleView)



## Koringar (9. Jun 2009)

Hi liebe Gemeinde,

ich versuche den ConsoleAppender des Log4J auf eine eigene ConsoleView innerhalb meiner RCP- Anwendung zu bekommen. Ich habe es schon hinbekommen, das mir eine ConsoleView angezeigt wird und sie auf System.out reagiert.
Jedoch wird der ConsoleAppender dadrin nicht angezeigt, muss ich da vielleicht noch irgend was einstellen?

Ich habe auch den Tip bekommen, vielleicht mal einen eigenen Appender zuschreiben. Habe da aber absolut null Erfahrung und meine suche in Google ergab auch nicht so das ware.

Habt ihr da vielleicht irgend welche Erfahrungen und könnt mir helfen?

MfG Koringar


----------



## Koringar (25. Jun 2009)

Hi,

nach langem Rätseln und Forschen, habe ich nun die Ursache gefunden  und sie ist auch ganz logisch. Dadurch das über die log4j.propertis (oder das XML Pendant) der ConsoleAppender schon ganz am Anfang des Programmes initialisiert wird und er sich da den StreamWriter auf System.Out holt, kann er nicht wenn ich das System.Out später auf einen anderen Stream änder darauf reagieren.

Einfachste Lösung dafür ist den ConsoleAppender über den Code leider einzufügen und zwar genau dann wenn man den System.Out umleitet.


```
import java.io.OutputStreamWriter;
import java.io.PrintStream;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;

public class ZeigeConsole extends AbstractHandler implements IHandler{

	public Object execute(ExecutionEvent event) throws ExecutionException {
		Logger logger = Logger.getLogger(StatusServerClient.class);
		ConsolePlugin plugin = ConsolePlugin.getDefault();

		IConsoleManager conMan = plugin.getConsoleManager();
		String systemConsoleName = "System.out";
		IConsole[] existing = conMan.getConsoles();
		for (int i = 0; i < existing.length; i++)
			if (systemConsoleName.equals(existing[i].getName()))
				return (MessageConsole) existing[i];

		MessageConsole systemConsole = new MessageConsole(systemConsoleName,
				null);
		conMan.addConsoles(new IConsole[] { systemConsole });

		MessageConsoleStream defaultMessageOutputStream = systemConsole.newMessageStream();
		PrintStream defaultMessagePrintStream = new PrintStream(defaultMessageOutputStream);
		
//		MessageConsoleStream warningMessageOutputStream = systemConsole.newMessageStream();
//		warningMessageOutputStream.setColor(new Color(Display.getCurrent(), 0,
//				0, 255));
//		PrintStream warningMessagePrintStream = new PrintStream(warningMessageOutputStream);

		MessageConsoleStream errorMessageOutputStream = systemConsole.newMessageStream();
		errorMessageOutputStream.setColor(new Color(Display.getCurrent(), 255,
				0, 0));
		PrintStream errorMessagePrintStream = new PrintStream(errorMessageOutputStream);

		System.setOut(defaultMessagePrintStream);
		System.setErr(errorMessagePrintStream);
		
		//Den ConsoleAppender auf die neue Console lenken
		ConsoleAppender systemOut = new ConsoleAppender();
		systemOut.setName("System.Out");
		systemOut.setWriter(new OutputStreamWriter(System.out));
		PatternLayout outLayout = new PatternLayout();
		outLayout.setConversionPattern("%d{[yyyy-MM-dd / HH:mm:ss:SSS]} - %-5p - %m ---> (%C.%M line:%L) %n");
		systemOut.setLayout(outLayout);
		logger.addAppender(systemOut);
		//-----------------------------------------------

		try {
			IWorkbenchPage page = PlatformUI.getWorkbench()
					.getActiveWorkbenchWindow().getActivePage();
			String id = IConsoleConstants.ID_CONSOLE_VIEW;
			IConsoleView view = (IConsoleView) page.showView(id);
			view.display(systemConsole);
		} catch (PartInitException e) {
			e.printStackTrace();
		}

		return null;
	}
}
```


----------



## geke (13. Okt 2009)

Hier die Alternative mit einem Log4J Appender, die etwas eleganter aber dennoch nicht perfekt ist. Der Appender muss leider weiterhin per Java Code hinzugefügt werden.

Das Vorgehen:
Es wird eine eigene MessageConsoleAppender Klasse, welche von AppenderSkeleton (Log4J) ableitet, programmiert. Dieser Appender wird beim Start der GUI (z.B. in der Perspective Klasse) geladen.
Initialisiert wird die Klasse durch:

```
// Init der Message Console
MessageConsole myConsole = new MessageConsole("MyConsole", null);
MessageConsoleStream stream = myConsole.newMessageStream();
// Init des Appenders
MessageConsoleAppender messageConsoleAppender = new MessageConsoleAppender(stream);
logger.getParent().addAppender(messageConsoleAppender);
```

Anbei noch die MessageAppenderKlasse:


----------



## maki (13. Okt 2009)

Man könnte die log4j Konfiguration (Proeprties oder XMl Datei)auch in ein sog. Fragment auslagern


----------



## dagmar (12. Nov 2009)

Hallo Koringar,
ich bin eben auf der Suche, meine RCP-Anwendung um ein Log-/Console-Window anzureichern. Zu diesem Thema fand ich deinen Post und dachte, das passt genau für mich. So habe ich versucht, Dein prima Stückchen mal bei mir einzubauen. 
Zuerst meckerte Eclipse die Abhängigkeit zu org.eclipse.ui.console an. Einfügen in die Dependencies brachte nicht den gewünschten Effekt. Dann habe ich es in meine Target-Plattform importiert und erhalte 150 neue Abhängigkeiten, die ich jetzt importieren soll???
deswegen folgende Frage: Was muss ich tun, dass das bei mir auch tut? Wäre toll, wenn Du mir helfen könntest!
Gruß
Dagmar


----------



## Koringar (13. Nov 2009)

Hi Dagmar,

also Grundsätzlich sind die PlugIn's notwendig:

org.eclipse.core.runtime;bundle-version="3.4.0"
org.eclipse.ui;bundle-version="3.4.2",
org.eclipse.ui.console;bundle-version="3.3.1"

und dann müsste das Commando was ich da geschrieben habe eigentlich reichen, damit das Funktioniert.
Wie führste denn dein Programm aus?


Jedoch habe ich festgestellt das die Lösung noch nicht das war ist und nur eine Übergangslösung, ich
werde mich aber mal noch an eine bessere Lösung ran setzen, da diese ab und zu noch Fehler schmeißt.


----------



## Koringar (13. Nov 2009)

Hehe,

und da ist sogar die bessere Version des ConsoleLog. Ich habe einfach einen eigenen Appender aus meinen Kenntnissen (Versuche) mit der Console einfließen lassen.

Hier der Code für den Appender:

```
import java.io.IOException;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;

import gui.Activator;

public class ConsoleLogAppender extends AppenderSkeleton {
	
	protected IConsoleManager conMan;
	protected String symbolicName;
	//Kann über die Log4J Propertie geändert werden, ist nur das Initallayout. Kann auch auf Debug gesetzt werden.
	protected String logLevel = "ERROR";
	
	@Override
	protected void append(LoggingEvent arg0) {
		if(conMan == null){
			conMan = ConsolePlugin.getDefault().getConsoleManager();
			symbolicName = Activator.getDefault().getBundle().getSymbolicName();
		}
		
		if (this.layout == null) {
			this.errorHandler.error("Missing layout for appender " +
					this.name,null,ErrorCode.MISSING_LAYOUT); 
		    return;
		}
		
		//Den Text so wie ihr in gerne haben wollt. Könnt ihn auch noch etwas erweitert, wenn ihr da noch was braucht was Log4J nicht braucht.
		StringBuffer text = new StringBuffer();
		text.append(this.layout.format(arg0));

		Level _level = arg0.getLevel();
		if(_level.toInt() >= Level.toLevel(logLevel).toInt()){		
			//Hollt jede Console die geöffnet ist	
			IConsole[] existing = conMan.getConsoles();
			for (int i = 0; i < existing.length; i++){
				//Und schreibt dann über den MessageStream auf die Console
				MessageConsoleStream stream =((MessageConsole) existing[i]).newMessageStream();
				try {
					stream.write(text.toString().getBytes());
					stream.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}			
		}
	}

	public void close() {
		conMan = null;
		symbolicName = null;
	}

	public boolean requiresLayout() {
		return true;
	}

	public String getLogLevel() {
		return logLevel;
	}

	public void setLogLevel(String logLevel) {
		this.logLevel = logLevel;
	}
}
```
Edit: Man kann dem Stream sicher auch noch ein paar Farben geben, bei Fehlern oder s, über setColor.


Zur übersicht halber hier der geänderte Code zum Commando, damit die Console aufgerufen wird:

```
import org.apache.log4j.Logger;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.MessageConsole;

import gui.Application;

public class ZeigeConsole extends AbstractHandler implements IHandler{
	
	private Logger logger = Logger.getLogger(this.getClass());

	public Object execute(ExecutionEvent event) throws ExecutionException {
			if(logger.isInfoEnabled())
				logger.info("Ausführen des Commandos " + this);
			ConsolePlugin plugin = ConsolePlugin.getDefault();
	
			IConsoleManager conMan = plugin.getConsoleManager();
			String systemConsoleName = "System.out";
			IConsole[] existing = conMan.getConsoles();
			for (int i = 0; i < existing.length; i++)
				if (systemConsoleName.equals(existing[i].getName())){
					((MessageConsole) existing[i]).activate();					
					return null;
				}
	
			if(logger.isDebugEnabled())
				logger.debug("Suche vorhandene Console oder erstelle eine Neue");
			MessageConsole systemConsole = new MessageConsole(systemConsoleName,
					null);
			conMan.addConsoles(new IConsole[] { systemConsole });

			try {
				if(logger.isInfoEnabled())
					logger.info("Anzeigen der Console");
				IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
				String id = IConsoleConstants.ID_CONSOLE_VIEW;
				IConsoleView view = (IConsoleView) page.showView(id);
				view.display(systemConsole);
			} catch (PartInitException e) {
				logger.error("Fehler beim Darstellen der Console", e);
			}
		return null;
	}
	
	@Override
	public void dispose() {
		ConsolePlugin plugin = ConsolePlugin.getDefault();
		IConsoleManager conMan = plugin.getConsoleManager();
		String systemConsoleName = "System.out";
		IConsole[] existing = conMan.getConsoles();
		for (int i = 0; i < existing.length; i++)
			if (systemConsoleName.equals(existing[i].getName())){
				((MessageConsole) existing[i]).destroy();
			}
	}
}
```

und die Log4J Property:

```
log4j.rootLogger=DEBUG, CONSOLEOUT

# ConsoleLogAppender ist ein eigene Appender, der in die interne Console schreibt
log4j.appender.CONSOLEOUT=(Eurer Package wo er liegt).ConsoleLogAppender
log4j.appender.CONSOLEOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLEOUT.layout.ConversionPattern=%d{[yyyy-MM-dd / HH:mm:ss:SSS]} - %-5p - %C.%M ---> %m (line:%L) %n
log4j.appender.CONSOLEOUT.logLevel=DEBUG
```

MfG Koringar


----------



## dagmar (17. Nov 2009)

Hi,
ich bring das jetzt zum Kompilieren, aber ganz blicke ich noch nicht durch: Wo wird denn der ConsoleLogAppender initialisert? Ich hatte das so in meiner Perspective drin:

```
public class Perspective implements IPerspectiveFactory {
	
	private Logger logger = Logger.getLogger(this.getClass());

	public void createInitialLayout(IPageLayout layout) {
		String editorArea = layout.getEditorArea();
		layout.setEditorAreaVisible(false);
		layout.setFixed(true);
		
		
		IFolderLayout folder = layout.createFolder("de.doxanize.main",
                IPageLayout.TOP, 0.95f, layout.getEditorArea());
		folder.addView(View.ID);
		//folder.addView(IConsoleConstants.ID_CONSOLE_VIEW);
		ConsoleLogAppender consoleLogAppender = new ConsoleLogAppender();
		logger.getParent().addAppender(consoleLogAppender);
	}

}
```

was dummerweise zur Folge hatte, dass kein View mehr angezeigt wurde ;(
Hast Du noch einen schlauen Hinweis für mich?
Das wäre so nett!
Gruß
Dagmar


----------



## Koringar (18. Nov 2009)

Hi,

der Appender wird so wie jeder andere Log4J Appender über die log4j.properties initialisiert. Du brauchst da nichts gesonders initialisieren, sobald eine Console da ist wird auf ihr geschrieben.


----------



## dagmar (18. Nov 2009)

Hurra, das tut! :applaus: Obercool, Viiiielen Dank!
Gruß
Dagmar


----------



## dagmar (18. Nov 2009)

Habe noch das Initialisieren der Konsole in eine (Singleton-)Klasse ausgelagert. Somit kann man von überall aus die Konsole initialisieren (im Beispiel macht das ja der Handler beim Aufruf des commands) und kann von Anfang an Logmeldungen sammeln.

```
public class LogUtil {

	private static LogUtil content;
	private Logger logger = Logger.getLogger(this.getClass());
	
	private LogUtil() {
	}
	
	public static synchronized LogUtil getInstance() { 
		if (content != null) { 
			return content; 
		} 
		content = new LogUtil(); 
		return content; 
	}
	
	public MessageConsole initConsole() {
		if(logger.isInfoEnabled())
			logger.info("Ausführen des Commandos " + this);
		ConsolePlugin plugin = ConsolePlugin.getDefault();

		IConsoleManager conMan = plugin.getConsoleManager();
		String systemConsoleName = "System.out";
		IConsole[] existing = conMan.getConsoles();
		for (int i = 0; i < existing.length; i++) {
			if (systemConsoleName.equals(existing[i].getName())){
				((MessageConsole) existing[i]).activate();
				return (MessageConsole) existing[i];
			}
		}
		if(logger.isDebugEnabled())
			logger.debug("Suche vorhandene Console oder erstelle eine Neue");
		MessageConsole systemConsole = new MessageConsole(systemConsoleName,null);
		conMan.addConsoles(new IConsole[] { systemConsole });
		return systemConsole;
	}

}
```


----------

