# log4j in eine Datei



## hdi (16. Apr 2009)

Hallo,
ich habe eine Webapp und wollte nun einen extra Logger (log4j) schreiben, der etwas in eine Datei loggt. Ich kenne mich damit nicht aus, habe versucht mittels einem Bsp das ich im Inet gefunden habe, es aufzuziehen. Ich denke (hoffe) so ganz daneben lieg ich nicht und es nicht ein kleiner Fehler, den ich nicht sehe.
(Natürlich ist das log4j-jar inkludiert, es geht ja auch, nur eben nicht mein zweiter Logger in die Datei.)

In die log4j.xml habe ich folgende Einträge hinzugefügt:

[XML]   <appender name="EmailAppender" class="pfad.zu.meinem.package.EmailAppender">
    <param name="file" value="emailSend.log" />
    <param name="Append" value="true" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern"
             value="%d{ISO8601} %-5p [%t] %c: %m%n" />
    </layout>
  </appender>

  <logger name="EmailLogger">
    <level value="INFO" />
    <appender-ref ref="EmailAppender" />
  </logger>[/XML]

Dann habe ich den Appender geschrieben, und zwar dort wo der Pfad des Appenders in der logj4 definiert ist. Also: pfad.zu.meinem.package.EmailAppender

Die Klasse sieht so aus:


```
package pfad.zu.meinem.package;

import java.io.*;
import org.apache.log4j.FileAppender;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

public class EmailAppender extends FileAppender
{
  private RandomAccessFile raFile;

  /** @see org.apache.log4j.FileAppender#activateOptions() */
  public void activateOptions()
  {
	  
    System.out.println("In emailappender:activateOptions()");
	  
    super.activateOptions();
    if( null == raFile ) {
      if( null != fileName ) {
        try {
          raFile = new RandomAccessFile( fileName, "rw" );
        } catch( FileNotFoundException ex ) { //
        }
      }
      if( null == raFile ) {
        LogLog.error( "Logdatei '" + fileName
                      + "' kann nicht angelegt werden fuer '"
                      + name + "'." );
      }
    }
  }

  /** @see org.apache.log4j.WriterAppender#subAppend(LoggingEvent) */
  protected void subAppend( LoggingEvent event )
  {
	System.out.println("In emailappender:subAppend()");
	  
    // Nicht 'super.subAppend(event)' aufrufen!
    if( null != raFile ) {
      try {
        raFile.seek( 0 );
        raFile.setLength( 0 );
        raFile.writeBytes( getLayout().format( event ) );
      } catch( IOException ex ) {
      }
    }
  }
}
```

In der Klasse, in der ich diesen Logger verwenden möchte, hole ich mir den einfach so:


```
private final static Logger logger = Logger
			.getLogger("EmailLogger");
```

Ich glaube hier liegt auch das Problem. Und zwar liegt diese Klasse in einem ganz anderen Web-Projekt, sie ist per jar in mein jetziges Projekt eingebunden. Allerdings befürchte ich dass sich die Zeile oben auf die log4j.xml des dortigen Projekts bezieht, in der es keinen "EmailLogger" gibt.

Eine Fehlermeldung gibts auch nicht, es geht nur einfach nicht. ICh sehe, dass die activateOptions() zwar aufgerufen wird, aber ich kann nirgendwo die sendMail.log Datei finden. (Wo wird die überhaupt abgespeichert?)

Kann mir irgendwer helfen bitte? Vielen Dank


----------



## maki (16. Apr 2009)

hdi,

wieso nicht einfach den FileAppender nehmen?

Eigene Appender schreibt man mit Log4J selten, gibt doch schon so viele, normalerweise konfiguiert man log4j nur mit XML/Property Dateien, ohne extra Java Klassen zu schreiben.


----------



## hdi (16. Apr 2009)

Also ich habe es jetzt nochmal so versucht:

in Projekt A steht in der log4j.xml der Eintrag:


```
<appender name="MAIL"
		class="org.apache.log4j.DailyRollingFileAppender">
		<param name="datePattern" value="'.'yyyy-MM-dd_HH-mm" />
		<param name="file" value="./mailsend.log" />
		<param name="Append" value="true" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern"
				value="%d %-5p [%t] %c: %m%n" />
		</layout>
	</appender>

	<logger name="org.*">
		<level value="INFO" />
		<appender-ref ref="MAIL" />
	</logger>
```

Die Klasse, die diesen Logger nutzt, *ist allerdings in Projekt B!*
Sie intantiiert den Logger wie folgt:


```
private final static Logger logger = Logger
			.getLogger("MAIL");
```

Wie gesagt, ich hab das Gefühl es geht nicht weil ja der Appender mit NAmen "MAIL" nicht in der log4j.xml von diesem Projekt (B) steht, sondern in der des Projekts A. (Beide haben eine log4j.xml).
Also diese Klasse ist eben in einem ganz anderen Projekt als dem, in dem in der log4j.xml der Appender definiert wird. Sie wird über ein jar eingeladen.

Resultat ist zumindest so nix. Ich sehe nirgendwo eine Datei namens "sendMail.log". :bahnhof:


----------



## maki (16. Apr 2009)

Ich verstehe ehrlich gesagt immer noch nicht was du vorhast..

Projekt A hat eine log4j konfig, Projekt B hat eine log4j konfig, somit hat die logging Konfig von Projekt A nix mit der von Projekt B zu tun, und umgekehrt.

Der Unterschied zwischen Logger und Appender ist dir klar?

Solltest deine Logger jedenfalls lieber so instanzieren:

```
private final static Logger logger = Logger
            .getLogger(DerNameDerKlasseDieLogt.class);
```


----------



## hdi (16. Apr 2009)

Ja aber ich will ja nur einen bestimmten Logger in der Klasse ansprechen. Oder so 
Also: Ich habe in meiner log4j.xml mehrere <logger>-blöcke.
Für gewisse packages gilt das log-level WARN, für andere das level DEBUG usw.
Das lvl, in dem ich in der besagten Klasse loggen will, ist INFO.
Allerdings kann ich das ja nicht einfach so machen, denn wenn ich will dass das geloggt wird muss ich den Logger (<root>) in der .xml ja auf INFO schalten. Aber dann loggt er ja auch alle info-statements aus anderen Klassen mit, was ich nicht will.

Oder kurz gesagt: Ich möchte 2 Logfiles haben. Eins speziell für nur diese Klasse, mit eigenem Logger und Loglevel, und ein anderes für alles andere.

Deshalb kann ich doch nicht einfach sagen logger.getLogger(meineKlasse.class), oder? Weil das spricht doch dann sozusagen den globalen Logger an.

Alle Loggings in einer speziellen Klasse sollen in eine bestimmte .log-Datei. Allerdings am besten im richtigen Projekt, das ist es ja. Die Datei aus der geloggt wird befindet sich in Projekt B. Muss ich jetzt in der log4j.xml von Projekt B oder A etwas ändern? Genutzt wird die Klasse nämlich in Projekt A.

Hoffe, das war verständlich?


----------



## SebiB90 (16. Apr 2009)

Was mir grad auffällt, dein Appender heißt "MAIL" und der logger "org.*". Aber der Logger muss doch "MAIL" heißen, wenn du über getLogger("MAIL") drauf zugreifen willst.


----------



## hdi (17. Apr 2009)

Ich glaube das ist schon so richtig?! Beim Namen vom Logger dachte ich gibt man an, für welche Klassen bzw. packages der Logger gilt. Wenn man einen lädt geht man über den Namen vom Appender. Oder stimmt das nicht?


----------



## maki (17. Apr 2009)

Logger am besten nach der Klasse benennen die loggt, so kann man auch steuern welche Logausgaben (also von welcher Klasse bzw. ganze Packet-"hierarchien") man möchte.
Appender werden ausschliesslich in der konfiguration festgelegt, zB. einer für die Konsole, einer für 'ne Datei, email, Windows Events, etc. pp.


----------



## hdi (17. Apr 2009)

Ja das wurde schon gesagt, und normalerweise log ich auch so. Aber ich kann nicht einfach nur die Klasse hinschreiben, ich möchte dass von dieser einen Klasse alle Log-Ausgaben in eine Extra Datei gehen, und einen extra Logger haben (müssen, weil das Log-Level von Loggings an anderen Stellen unterschiedlich eingestellt werden muss). Aber ich peil's nicht, wie man das einstellen muss.
...Ich weiss nicht, ob ihr noch immer nicht versteht was ich machen will?


----------



## maki (17. Apr 2009)

Du musst einen Logger und einen Appender Konfigurieren.
Der Appender schreibt eben in eine Datei, der Logger sorgt dafür dass nur die gewünschte(n) Klassen/Packete geloggt werden und referenziert den Appender.

Schon gelesen? Log4jXmlFormat - Logging-log4j Wiki


----------



## SebiB90 (17. Apr 2009)

hdi hat gesagt.:


> Ich glaube das ist schon so richtig?! Beim Namen vom Logger dachte ich gibt man an, für welche Klassen bzw. packages der Logger gilt. Wenn man einen lädt geht man über den Namen vom Appender. Oder stimmt das nicht?


Also irgendwie nicht. Wenn du mit getLogger("MAIL") ein Logger holst, forderst du einen Logger mit dem Namen MAIL an. Dann musst du auch ein Logger mit diesen Namen konfigurieren und nicht mit dem Namen der Klasse. Wenn du den Logger mit dem Namen der Klasse benennst, musst du dir den Logger auch über den Klassennamen besorgen im Programmcode


----------



## hdi (17. Apr 2009)

@maki genau das hab ich ja erst versucht (siehe erster Post).
@sebi ich hab hier eine log4j.xml, die nicht ich geschrieben habe, aber nun eben ändern muss.Da werden nie Namen für die <logger>-Blöcke vergeben, immer nur die packages oder Klassen für die das gilt.

Also, kann mir nicht einer bitte ein Bsp geben, wie das aussehen muss. Ich denke ja nach wie vor dass man die Tatsache, dass es hier um 2 verschiedene Projekte geht, nicht ignorieren kann. Ich weiss ja nicht mal genau, in welche der beiden log4j.xml ich das eintragen muss. Wenn mir das jmd konkret zeigen könnte, wie man das schreibt, wäre ich sehr dankbar dafür. Meine Versuche funzen einfach nicht, und es ist ja nicht so dass man Fehlermeldung o.ä. kriegt - es passiert einfach nix.


----------



## maki (17. Apr 2009)

> @maki genau das hab ich ja erst versucht (siehe erster Post).


Nein, hast du nicht 

Im ersten Post hattest du deinen eigenen Appender _geschrieben_, nicht _konfiguriert_.
Dazu kommt, dass du veruscht hast den Appender direkt per Namen anzusprechen(MAIL), was gar nicht gehen kann.

Mal sehen ob ich ein Beispiel "on-the-fly" erstellen kann das nicht zu viele fehler hat:
[xml]
..
  <appender name="FileAppender" class="org.apache.log4j.RollingFileAppender"> 
    <param name="file" value="example.log"/>
    <param name="MaxFileSize" value="100KB"/>
    <!-- Keep one backup file -->
    <param name="MaxBackupIndex" value="1"/>
    <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%p %t %c - %m%n"/> 
    </layout> 
  </appender>

...

  <logger name="deine.packete.oder.gar.konkrete.klassen" additivity="false">
    <level value="info"/>
    <appender-ref ref="FileAppender" />
  </logger>

[/xml]
Und in deiner Klasse dann den normalen Weg wählen um einen Logger zu erhalten/festzulegen.


----------



## hdi (17. Apr 2009)

danke maki ich werd's später in der Arbeit probieren!


----------



## hdi (17. Apr 2009)

Ok also es geht aus irgendeinem grund noch immer nicht 

Ich hab deinen Code übernommen, natürlich den Pfad zur Klasse angepasst, und dann in der dort spezifierten Klasse den Logger einfach via getLogger(dieseklasse.class) geladen. Aber es funktioniert nicht. Denke ich zumindest. Wo soll denn die Log-Datei dann liegen?  Über die Windows-Suchfuntkion wird zumindest nix gefunden.

Auch wenn ich euch damit vllt nerve, aber ich bin noch immer nicht gaaaanz 100%ig sicher ob ihr mein Szenario versteht 

Nochmal sehr ausführlich, weil ich denk ich drück mich einfach nich richtig aus:

Ich habe 2 Java-Webprojekte, Projekt A und Projekt B. Projekt A inkludiert das jar von Projekt B. Also Projekt A hat Zugriff auf alle Sourcen von Projekt B. Die Datei, in der das gewünschte Logging stattfinden soll, befindet sich in Projekt B.

Jetzt haben aber sowohl Projekt A als auch Projekt B eine log4j.xml.

In welche der beiden muss das jetzt nun rein? Also ich meine: Wenn ich die Datei ausführe, die aus dem jar von Projekt B kommt, aber das ganze passiert innerhalb meiner Projekt-A Applikation, also zur Runtime, welche log4j wird beim Logging angesprochen? Ich check's einfach nicht, es geht nich wie ich's dreh und wende.

Was ich mich auch frag: Was genau besagt dieser root-Eintrag? Was ist wenn root auf WARN gesetzt ist, und mein Logger für den Appender auf INFO? Wird das überhaupt ausgegeben?

PS: absoluter pfad hab ich versucht, die Datei gibt's nicht


----------



## maki (17. Apr 2009)

Gib doch einen absoluten Pfad ein zum Testen, dann musst du nicht suchen.


----------



## hdi (17. Apr 2009)

gab n edit grad, wir haben gleichzeitig geschrieben (siehe bitte mein letzter post)


----------



## maki (17. Apr 2009)

Es wird nur eine einzige log4j Konfig ausgewertet, nämlich die, die zuerst gefunden wird.
Welche das ist hängt vom CP ab...

Vielleciht editierst du die falsche 

Der root logger ist die Wurzel, soz. das allgemeine Logginglevel für alles was nicht genauer spezifiziert ist, solltest diesen Wert normlaerweise hoch setzen (WARN zB).


----------



## hdi (17. Apr 2009)

```
Es wird nur eine einzige log4j Konfig ausgewertet, nämlich die, die zuerst gefunden wird.
```
NAja innerhalb meiens Projekts gibt es ja nur eine. Die Frage ist ob die vom anderen Projekt beachtet wird, weil ja auch Dateien vom anderen projekt genutzt werden. Aber scheinbar ja nicht.

Nach wie vor... es geht einfach nicht  Ich hab echt kA mehr was da los ist

*edit: Hier mal die volle logj4.xml*

[XML]<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern"
				value="%p - %C{1}.%M(%L) | %m%n" />
		</layout>
	</appender>

	<appender name="FILE"
		class="org.apache.log4j.DailyRollingFileAppender">
		<param name="datePattern" value="'.'yyyy-MM-dd_HH-mm" />
		<param name="file" value="./xxxxxxxx.log" />
		<param name="Append" value="true" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern"
				value="%d %-5p [%t] %c: %m%n" />
		</layout>
	</appender>

	 <appender name="MailAppender" class="org.apache.log4j.RollingFileAppender"> 
    <param name="file" value="./mailsend.log"/>
    <param name="MaxFileSize" value="100KB"/>
    <!-- Keep one backup file -->
    <param name="MaxBackupIndex" value="1"/>
    <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%p %t %c - %m%n"/> 
    </layout> 
  </appender>

  <logger name="paket.von.anderem.projekt.über.jar.DieKlasse" additivity="false">
    <level value="INFO"/>
    <appender-ref ref="MailAppender" />
  </logger>

	<logger name="com.xx.xxx.xx">
		<level value="WARN" />
		<appender-ref ref="" />
	</logger>

	<logger name="org.*">
		<level value="WARN" />
		<appender-ref ref="FILE" />
	</logger>

	<root>
		<level value="WARN" />
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
	</root>
</log4j:configuration>[/XML]


----------



## maki (17. Apr 2009)

> NAja innerhalb meiens Projekts gibt es ja nur eine. Die Frage ist ob die vom anderen Projekt beachtet wird, weil ja auch Dateien vom anderen projekt genutzt werden. Aber scheinbar ja nicht.


Kannst du die vom anderen Projekt mal rausschmeissen?


----------



## hdi (17. Apr 2009)

Ich hab die vom andren mal umbeannt in "whatever.xxx". Aber es geht noch immer nicht, ich hab jetzt n absoluten Pfad angegeben für die Datei beim Appender ("C:/mailsend.log"), aber sie ist nicht da.

...das kann aber nix damit zu tun haben dass ich hier auf localhost arbeite oder? Also.. bin nach wie vor ratlos ;(

edit: In der xml wo ich geschrieben hab

paket.von.anderem.projekt.über.jar.DieKlasse

das habe ich also ganz normal mit dem package-namen von dem anderen Projekt geschrieben. Da muss ich ja jetzt nich irgendwie n komischen Pfad angeben weil ich es aus ner jar lade oder? Immerhin mache ich die imports genauso und es klappt alles.


----------



## hdi (17. Apr 2009)

Sooo Leute es klappt! Die Kombination aus einer scheinbar nicht funktionierenden Windows-Suche und meiner Unwissenheit darüber, wo die Dateien landen, haben mich denken lassen es ginge nicht. Aber es passt jetzt 
*Vielen Dank an alle!!!*


----------

