# log4j: WriterAppender



## byte (27. Aug 2006)

Hallo,

ich nutze log4j zum Logging in meiner Anwendung und gebe es in einer Konsole in der GUI meiner Anwendung aus. Das habe ich bisher so gemacht, dass ich als Appender einen ConsoleAppender verwende. Dazu habe ich einen neuen PrintStream geschrieben, der die Daten in meine GUI schreibt und diesen habe ich als neuen System.out gesetzt. Das funktioniert auch soweit ganz gut.

Jetzt möchte ich aber nicht mehr den Umweg über den System.out gehen. Daher dachte ich mir, ich nutze als Appender den _WriterAppender_:


XML-Config:

```
<appender name="Console2" class="org.apache.log4j.WriterAppender">
     <param name="Writer" value="de.tubs.jlsc.util.Loggers.out"/>
     <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="[%d{HH:mm:ss}] Executing :  %m%n"/>
     </layout>
  </appender>
```

Java Code:

```
package de.tubs.jlsc.util;

public interface Loggers {
	
        ...
	
	PrintStream outExecution = new PrintStream(new OutputStream() {
		public void write(final int b) {
                        //hier schreibe ich in die GUI (der Code ist korrekt):
			Display.getDefault().asyncExec(new Runnable() {
				public void run() {
					Application.getInstance().getExecutionConsole().append(String.valueOf((char) b));
				}
			});
		}
	});
	
	Writer out = new OutputStreamWriter(outExecution);
}
```

Ich kriege aber jedes mal eine Fehlermeldung:



> log4j:WARN Failed to set property [writer] to value "de.tubs.jlsc.util.Loggers.out".



Im Internet findet man irgendwie so gut wie keine Informationen über den log4j WriterAppender. Und ich kann beim besten Willen nicht nachvollziehen, warum das nicht funktioniert. Kann mir jemand helfen? Oder gibts vielleicht eine andere Lösung, wie man die Logging Messages in eine GUI bekommt?

Danke im Voraus!

MFG byto


----------



## Pulvertoastman (31. Aug 2006)

Vielleicht hilft dir ein Blick in die API:
http://logging.apache.org/log4j/docs/api/org/apache/log4j/WriterAppender.html

Dort wirst du sehen, dass z:B. der ConsoleAppender darauf basiert. Beim Setzen des Writers steht auch eine kleine Warning.

Ich vermute mal, dass du von dem Appender ableiten musst und dann selber den Writer im Code setzt.

hth
/dirk


----------



## byte (6. Sep 2006)

> Ich vermute mal, dass du von dem Appender ableiten musst und dann selber den Writer im Code setzt.



Wie kommst Du darauf? WriterAppender ist nicht abstrakt, also sollte es auch ohne Vererbung klappen.

Und die Warnung sagt nur, dass der Writer nicht geschlossen sein darf und das ist er ja bei mir nicht.


----------



## Pulvertoastman (7. Sep 2006)

das die klasse nicht abstrakt ist, heisst ja nicht unbedingt, dass du sie so verwenden kannst. Das hatte ich so ja auch nicht behauptet.

die warnung sagt aber auch



			
				http://logging.apache.org/log4j/docs/api/org/apache/log4j/WriterAppender.html#setWriter(java.io.Writer) hat gesagt.:
			
		

> The specified Writer must be opened by the user and be writable.



hast du das auch gelesen?


----------



## byte (7. Sep 2006)

Ja, die Warnung habe ich gelesen. Aber ein Writer ist doch automatisch geöffnet, wenn man ihn erzeugt und zwar solange, bis das close() kommt. Oder wie soll ich ihn Deiner Meinung nach öffnen?



> das die klasse nicht abstrakt ist, heisst ja nicht unbedingt, dass du sie so verwenden kannst. Das hatte ich so ja auch nicht behauptet.



Natürlich kann ich eine Klasse verwenden, wenn sie nicht abstrakt ist und öffentliche Konstruktoren hat. Und das trifft ja in diesem Fall zu. Und es steht auch weder in der log4j Wiki noch in der API, dass man WriterAppender nicht verwenden darf.



> WriterAppender appends log events to a Writer or an OutputStream depending on the user's choice.


----------



## Pulvertoastman (7. Sep 2006)

byto hat gesagt.:
			
		

> Ja, die Warnung habe ich gelesen. Aber ein Writer ist doch automatisch geöffnet, wenn man ihn erzeugt und zwar solange, bis das close() kommt. Oder wie soll ich ihn Deiner Meinung nach öffnen?



Ich denke, dass die Konfiguration des Wrtiers nicht passt und deswegen der Writer nicht gesetzt wird. Soweit ich weiss, kann der Writer nur über die API gesetzt werde. Bin da aber nicht wirklich sicher.



			
				byto hat gesagt.:
			
		

> Natürlich kann ich eine Klasse verwenden, wenn sie nicht abstrakt ist und öffentliche Konstruktoren hat. Und das trifft ja in diesem Fall zu.



ja kannst du. dagegen wollte ich auch nichts sagen. fraglich bleibt halt bloss, ob das objekt sich dann so verhält wie du denkst, dass es sich verhalten soll. wenn der writer naemlich nicht gesetzt wird, hast du vielleicht ein problem.


----------



## byte (7. Sep 2006)

Pulvertoastman hat gesagt.:
			
		

> Soweit ich weiss, kann der Writer nur über die API gesetzt werde. Bin da aber nicht wirklich sicher.



Das wäre ja ziemlich blöd, denn dann könnte man sich die XML Konfiguration ja schenken. Laut log4j Wiki kannst Du alles auch per XML setzen, somit auch den Writer:



> The details of the configuration for a specific appender class vary from class to class. Your best bet is to review the javadoc for the appender class you want to use. Pay particular attention to the setter property methods and the values they expect. Each setter method can be accessed using the param element in the xml configuration.



Quelle: http://wiki.apache.org/logging-log4j/Log4jXmlFormat



> ja kannst du. dagegen wollte ich auch nichts sagen. fraglich bleibt halt bloss, ob das objekt sich dann so verhält wie du denkst, dass es sich verhalten soll. wenn der writer naemlich nicht gesetzt wird, hast du vielleicht ein problem.



Meinst Du nicht, dass dann irgendwas dahingehend in der API Doc von WriterAppender stehen würde, wenn man diese nicht verwenden darf? Das tut es aber nicht. Und mal ganz unter uns: Ein Framework, das Klassen enthält, die man zwar instanzieren kann aber nicht darf, ist gelinde gesagt ziemlich dämlich entworfen.  Denn es gibt ja genug Möglichkeiten, die Instanzierung einer Klasse zu verhindern: Klasse abstrakt machen, Konstruktoren private setzen, ...


----------



## Pulvertoastman (7. Sep 2006)

Keine Ahnung. hast du schon mal versucht, das log4j interne debugging zu aktivieren?



> <log4j:configuration debug="true" xmlns:log4j='http://jakarta.apache.org/log4j/'>



Daneben habe ich dann auch mal die Ursache gefunden, warum mir das so im Hinterkopf herumschwirrte:
http://thread.gmane.org/gmane.comp.jakarta.log4j.user/7458/focus=7460

Das passt auch irgendwie zu deiner Fehlermeldung.

Die Doku ist in dem Fall sicherlich nicht korrekt.


----------



## byte (7. Sep 2006)

Danke für den Link. Das riecht dann ja sehr nach Bug.

Mittlerweile habe ich mir aber sowieso überlegt, dass ich das ganze anders löse, und zwar mit einem eigenen Logger auf Basis von log4j. Dann kann ich in dem Zusammenhang gleich noch andere Sachen mit anpassen.

Thanks anyway.


----------

