# eigener logger mittels classe (dynamische logfilename) log4j



## gast (22. Nov 2006)

hallo leute,

proge gerade eine webanwendung mittels tomcat, axis,...

zum loggen verschiedener meldungen verwende ich die log4j.properties sowie eine eigene logger-classe:


```
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.FileAppender;


public class JusERVRCodeLog4j {

	private static Logger logger = null;
	
	public myLog4j(String logfile, Class _class){
		 logger = Logger.getLogger(_class);
		 String pattern = "%-5p;%d{yyyy-MM-dd HH:mm:ss};%m%n";
		 PatternLayout layout = new PatternLayout(pattern);
		 FileAppender appender = null;
		 try {
			 appender = new FileAppender(layout,logfile,true);
		 } 
		 catch(Exception e){
			 System.out.println(e.getMessage());
		 }
		 logger.addAppender(appender);
		 logger.setAdditivity(false);
		 logger.setLevel((Level) Level.INFO);
	}
	
	public void setDebug(Object arg0){
		logger.debug(arg0);
	}
	public void setInfo(Object arg0){
		logger.info(arg0);
	}
	public void setWarn(Object arg0){
		logger.warn(arg0);
	}
	public void setError(Object arg0){
		logger.error(arg0);
	}
	public void setFatal(Object arg0){
		logger.fatal(arg0);
	}
}
```

die klasse wird in mehreren anderen klasse instanziert.
myLog4j log = new myLog4j("log.txt",klasse.class);
nun werden ja die logs geschrieben jedoch nicht nur einmal sonder jedesmals n+1, wobei
n die anzahl der aufrufe des service ist.

nun glaub ich das dies deshalb passiert weil des object log nicht zerstört wird.
wie kann ich die mehrfachen log einträe vermeiden und trozdem bestimmen wie die logdatei heist.

danke mfg peter


----------



## Murray (22. Nov 2006)

Ist es Absicht, dass das Member logger static deklariert ist? So erzeugst du immer, wenn du den Konstruktor für eine andere Klasse aufrufst, einen neuen Logger, der dann von allen vorher entstandenen Instanzen verwendet wird. Wenn du den Konstruktor hingegen zweimal für die gleiche Klasse aufrufst, dann wird kein neuer Logger erzeugt (Logger#getLogger liefert dann die existierende Instanz zurück); du hängst aber trotzdem an diesen Logger einen weiteren Appender an, wodurch die Einträge dann dopplet protokolliert werden dürften.


----------



## wranger (22. Nov 2006)

> ```
> logger = Logger.getLogger(_class);
> ```


Wie soll das denn funktionieren?

 Den logger müsstest du doch bei jeder neuen Klasseninstanz überschreiben? Oder irre ich?


----------



## gast (22. Nov 2006)

auch wenn ich den logger nicht statisch deklariere erhalte ich merfache gleiche einträge im logfile.

peter


----------



## Murray (22. Nov 2006)

gast hat gesagt.:
			
		

> auch wenn ich den logger nicht statisch deklariere erhalte ich merfache gleiche einträge im logfile.



Wenn du den Konstruktor mehrfach für die gleiche Klasse aufrufst, muss das wohl passieren (s.o.). Vermutlich muss du noch irgendwie unterscheiden, ob Logger#getLogger ein neues Objekt erzeugt hat, oder ob du eine existierende Instanz bekommen hast.


----------



## byte (22. Nov 2006)

AFAIK erben doch alle Logger in der Hierarchie die Appender. Du musst also nur einmal auf dem Top-Level Logger den Appender hinzufügen.


----------



## gast (23. Nov 2006)

byto hat gesagt.:
			
		

> AFAIK erben doch alle Logger in der Hierarchie die Appender. Du musst also nur einmal auf dem Top-Level Logger den Appender hinzufügen.



das würde doch bedeuten das ich den appender im log4j.properties file anlegen muß, wie kann ich dann dan ort und den namen des logfiles zur laufzeit bestimmen

mfg peter


----------



## byte (23. Nov 2006)

Ob Du das nun über Properties, XML oder direkt im Code angibst, spielt keine Rolle. Wenn Du allen Loggern den gleichen Appender zuweisen willst, dann appende den am besten beim Root-Logger, denn von dem erben alle weiteren Logger.


```
Logger.getRootLogger();
```


----------



## zc (23. Nov 2006)

das problem ist das ja auch noch andere logger laufen die mit mylog nicht zu tun haben.

zusätzlich läuft ein sys.log der über log4j.properties bestimmt ist und ein rootLogger


```
# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=INFO, LOGFILE
log4j.category.SYS=INFO, SYSLOG

# Set the enterprise logger category to FATAL and its only appender to LOGFILE.
log4j.logger.org.apache.axis.enterprise=FATAL, LOGFILE 

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.Threshold=FATAL
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%-5p;%d{yyyy-MM-dd HH:mm:ss};%-4r;[%t];%c;%x;%m%n

# SYSLOG is set to be a File appender using a PatternLayout.
log4j.appender.SYSLOG=org.apache.log4j.FileAppender
log4j.appender.SYSLOG.File=sys.log
log4j.appender.SYSLOG.Append=true
log4j.appender.SYSLOG.Threshold=ERROR
log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.SYSLOG.layout.ConversionPattern= %-5p;%d{yyyy-MM-dd HH:mm:ss};%m%n
```

der SYS Logger wird auch über eine Java-Class angestossen hat also mit mylog nichts zu tun.

ich brauch den mylog um für verschiedene user eigene log-files zu schreiben. d.h. ja nach dem welcher user das service aufruft (angemeldet ist) muß das xxx.log bestimmt werden und auch nur in dieses geschrieben werden.


----------



## byte (23. Nov 2006)

OK, und was ist nun genau das Problem? :roll:


----------



## zc (23. Nov 2006)

byto hat gesagt.:
			
		

> OK, und was ist nun genau das Problem? :roll:



nun ja das die logeinträge doppelt und mehrfach im erstellt werden, pro ausruf des service n+1


----------



## Murray (23. Nov 2006)

Du machst also etwas in der Art:

```
myLog4j( "logfile_fuer_user_1", MyFabulousService.class);
myLog4j( "logfile_fuer_user_2", MyFabulousService.class);
```

Dann schlägt der bereits beschriebene Effekt zu: Logger#getLogger liefert zu einem Namen (resp. einer Klasse) nur eine Instanz zurück. Beim ersten Aufruf bekommst du also einen neuen Loger, und alles ist gut. Beim zweiten Aufruf bekommst du aber das selbe Logger-Objekt zurück wie beim ersten Aufruf. Diesem Logger-Objekt verpasst du dann einen weiteren Appender, wodurch alle Meldungen dann in beiden Log-Files landen dürften.

//EDIT: Typos


----------



## zc (23. Nov 2006)

ja stimmt so mach ich das, programmiere jetzt schon ein ganze weil daran herum und komme auf keinen grünen zweig,

ich möchte bloß das log file für mylog dynamisch zu laufzeit des services bestimmen.

vielleicht bin ja mit meinem ansatz völlig falsche.


----------



## wranger (23. Nov 2006)

Hallo,

wie implementiert man denn nu so eine Logger-Klasse, kann hier auch allgemein sein. Erstellt man die, erzeugt nur ein Objekt und übergiebt dieses dann an all die Klassen die erzeugt werden. Oder gibt es auch einen weg ohne expliziete Übergabe an die Klasse. Oder über eine statische Klasse?

@Ontopic in deinem Fall würde ich einen statischen Zähler einbauen der das append nur macht wenn der zähler kleiner als 1 ist.


```
class logger{
private static zaehler;
logger()
{
zaehler++;
}
public methode(){
if(zaehler <2)
 logger.append();
}
}
```


----------



## byte (24. Nov 2006)

Ich verstehe das Problem echt gar nicht. Du musst doch einfach nur zusehen, dass Du lediglich *einmal* pro User dem Logger einen Appender mit dem entsprechenden Userfile zuordnest. ???:L


----------



## Murray (24. Nov 2006)

Dazu müsste man vermutlich dafür sorgen, dass es für jede Klasse auch pro Benutzer einen eigenen Logger gibt. 


```
public myLog4j(String logfile, Class _class){
       logger = Logger.getLogger( _class.getName() + "-" + logfile);
 /* ...*/
```

Mit doppelten Einträgen ist dann allerdings immer noch zu rechnen, wenn myLog4j mehrfach mit den gleichen Parametern aufgerufen wird.


----------

