Log4jLogger Konfiguration zur Laufzeit

clumsy

Grünschnabel
Hallo,

ich schreibe ein Programm und nutze für das Logging log4j von apache. Ich rufe mein Programm mit Parametern auf, von denen auch welche in den Logdatei-Namen einfließen sollen, von daher kann ich diesen nicht in der log4j.properties hinterlegen.

Ich erzeuge dann den Logger folgendermaßen:

Java:
private static Logger filelogger = Logger.getLogger("FileLogger");

die folgende Methode soll den Logger bearbeiten:

private void handleLogging() throws DeployToolException {

        String logfile = properties.getProperty(Properties.DEPLOY_SERVER_ROOT_DIR);
        logfile += properties.getProperty(Properties.DEPLOY_SERVER_LOG_DIR);
        logfile += "/";
        logfile += properties.getProperty(Properties.DEPLOY_SERVER_LOG_FILE);
        logfile += ".";
        
        SimpleDateFormat fmt = new SimpleDateFormat();
        fmt.applyPattern( "yyyyMMdd-HHmmss" );
        Calendar cal = Calendar.getInstance();
        logfile += fmt.format(cal.getTime());

        logfile = logfile.replaceAll(" ", "_");

        String fileloglevel = properties.getProperty(Properties.DEPLOY_SERVER_FILE_LOG_LEVEL);
        String consoleloglevel = properties.getProperty(Properties.DEPLOY_SERVER_CONSOLE_LOG_LEVEL);

        String logpattern = "";
        DeployToolMode mode = new DeployToolMode();
        if (mode.isReleaseMode()) {
            logpattern = properties.getProperty(Properties.DEPLOY_SERVER_LOG_PATTERN_RELEASE);
        }
        else {
            logpattern = properties.getProperty(Properties.DEPLOY_SERVER_LOG_PATTERN_DEBUG);
        }

        try {
            PatternLayout layout = new PatternLayout(logpattern.toString());
            FileAppender fileAppender = new FileAppender(layout, logfile.toString(), false);
            filelogger.addAppender(fileAppender);
            filelogger.setLevel(Level.toLevel(fileloglevel.toString(), Level.DEBUG));
            
            ConsoleAppender consoleAppender = new ConsoleAppender(layout);
            consolelogger.addAppender(consoleAppender);
            consolelogger.setLevel(Level.toLevel(consoleloglevel.toString(), Level.INFO));
        }
        catch (Exception ex) {
            throw new DeployToolException(DeployToolMessage.getProperties().getMessage("e102", logfile, ex.toString())); // Beim Erstellen der Log-Datei ist ein Fehler aufgetreten
        }
        
        DeployToolMessage.getProperties().logger("i101", logfile); // Das log für diesen Auftrag findet man in:
    }

Führe ich das Programm aus bekomme ich zwei Warnungen, weil er die Konfiguration zu dem Logger FileLogger nicht finden kann, logisch! Aber wenn ich in der log4j.properties einen FileAppender angebe braucht dieser auch einen Dateinamen und den kann ich nicht nehmen, da dieser erst zur Laufzeit bestimmt werden soll.
Kann mir jemand helfen? Wie kann ich zur Laufzeit einen Logger erzeugen der in ein Datei schreibt ohne, dass er vorher in der log4j.properties aufgeführt ist und ohne dass warnings bei der Ausführung entstehen.

Vielen Dank Euch
Clumsy
 
Zuletzt bearbeitet:
vielleicht muss man einen eigenen FileAppender schreiben, der sich nicht gleich verunsichert fühlt, wenn er keinen Ausgangsdateinamen in der Konfiguration erhält.

(was anderes fällt mir da leider nicht ein)
 
1. benutze Java oder code tags [code=java] [/code]

2. Am besten baust du deinen eigenen FileAppender, wie schon von takidoso erwähnt.

3.
Java:
String logfile = properties.getProperty(Properties.DEPLOY_SERVER_ROOT_DIR);
logfile += properties.getProperty(Properties.DEPLOY_SERVER_LOG_DIR);
logfile += "/";
logfile += properties.getProperty(Properties.DEPLOY_SERVER_LOG_FILE);
logfile += ".";

Das ist sowas von inperformant. Da er jedes Mal einen neuen String erstellen muss.
Benutze hier StringBuilder oder versuch alles auf einmal zu einem String zusammenzubauen.

4. Suchen hilft ;-) http://www.google.de/search?hl=de&q=log4j+file+dynamisch&btnG=Suche&meta=
 
@Anime-Otaku: Solche simplen Stringkonkatenationen sind meist gar nicht imperformant weil der Compiler dieser erkennen und compilieren kann. Und Performance sollte auch (wenn nicht unbedingt nötig) zu lasten der Lesbarkeit gehen.

@clumsy: Du kannst in deiner log4j.properties System-Properties verwenden. Das müßte so gehen: ${logfile}. In deinem Programm kannst du vorm initialisieren entsprechend mit System.setProperty("logfile","") diese Property setzen.
 
Hallo,
stimmt, dass mit den Properties ginge auch. IMHO kommt es aber dann darauf an, wie dynamisch das ganze sein soll.

Ich hatte mal das Problem gehabt, dass der Log-Dateiname zusammengesetzt aus Eingangsdateiname, einem Prefix und Zeitstempel gebastelt werden sollte.
Ich bin mir nicht sicher, ob soetwas über die System-Properties auch bewerkstelligt werden könnte. Daher habe ich mir damals/neulich einen Appender erstellt

Java:
package de.cmk.log4j;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.log4j.FileAppender;

import de.cmk.util.AutoCounter;
import de.cmk.util.generate.StringComposer;


public class NameComposingFileAppender extends FileAppender
{
	private String m_inputRegex       = null;
	private String m_str4Constr       = null;
	private Map    m_autoCounterMap   = new HashMap();
	
	public void activateOptions() 
	{
		
		if (m_inputRegex==null)
		{
			StringComposer strComp = new StringComposer(new HashMap(), fileName);
			fileName = strComp.constructString();
		}
		else if (m_str4Constr==null)
		{
			errorHandler.error("String4Construction-Property has to be given when InputRegex are set!");
		}
		else
		{
			StringComposer strComp = new StringComposer(m_autoCounterMap,
														m_inputRegex,
														m_str4Constr,
														fileName);
			fileName = strComp.constructString();
		}
		
		super.activateOptions();
	}
	
	public void setString4Construction(String str4Constr)
	{
		m_str4Constr = str4Constr;
	}
	
	public void setInputRegex(String inputRegex)
	{
		m_inputRegex = inputRegex;
	}
	
	public void setAutoCounters(String autoCountersDefs)
	{
		//Trennung der Autocounterdefinitionen von einander Delimeter sei  "##"
		String[] acPropStrs = autoCountersDefs.split("#{2}");
		for (int i=0; i< acPropStrs.length; i++)
		{
			//Trennung der Properties eines Autocounters Delimeter sei ";"
			String propDefsStr = acPropStrs[i].trim().replaceAll(";", "\n");
			Properties props = new Properties();
			try
			{
				// Erstellen der Properties und instanziieren des Autocounters
				props.load(new ByteArrayInputStream(propDefsStr.getBytes()));
				AutoCounter ac = new AutoCounter(props);
				m_autoCounterMap.put(ac.getName(), ac);
			}
			catch (IOException ioEx)
			{
				throw new RuntimeException(ioEx);
			}
		}
	}
}

Ansprechen über die xml-Konfiguration kann man in beispielsweise wie folgenderweise
Code:
<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 
<appender name="jdtaconv" class="de.cmk.log4j.NameComposingFileAppender"> 
        <param name="string4Construction" value="${inputfilename}"></param>        
        <param name="inputRegex" value="(.*)"></param>
        <param name="file" value="/tmp/MEINVERZEICHNIS/trallala.{yyyy-MM-dd_HH-mm-ss-SSS}.(0).log" ></param> 
        <param name="Append" value="false" /> 
        <layout class="org.apache.log4j.PatternLayout"> 
                <param name="ConversionPattern" 
                      value="%d{ISO8601} %-5p %m%n" /> 
        </layout> 
</appender> 

<category name="de.tai.jdtatool2"> 
        <priority value="TRACE" ></priority> 
        <appender-ref ref="jdtaconv" /> 
</category> 

</log4j:configuration>
Hier sei angemerkt, dass in diesem Beispiel inputfilename eine von der Logger benutztenden Anwendung programmatisch gesetzte System-Property ist.

Vielleicht ist diese Klasse ja ein wenig inspirativ :p

In diesem Sinne

Takidoso

PS: hier noch ein anderes Beispiel einer Konfiguration
Code:
<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 
<appender name="jdtaconv" class="de.cmk.log4j.NameComposingFileAppender"> 
        <param name="string4Construction" value="${inputfilename}"></param>        
        <param name="inputRegex" value="([\\w[\\-]]*)\.([\\w[\\-]]*)\.([\\w[\\-]]*)\.([\\w[\\-]]*)\.(.*)"></param>
        <param name="autoCounters" 
               value="Name=sqn01;FileName=sqn01.ac;FirstValue=2;LastValue=10;Increment=4;ResetEachDay=FALSE;Cycle=TRUE;FileAutoCreation=TRUE
                    ##Name=sqn02;FileName=sqn02.ac;FirstValue=1;LastValue=10;Increment=3;ResetEachDay=FALSE;Cycle=TRUE;FileAutoCreation=TRUE"></param>
        <param name="file" value="logs/${user.name}/(1).{yyyy-MM-dd_HH-mm-ss-SSS}.(2).(3).(4).&lt;sqn01:000&gt;.&lt;sqn02:0000&gt;.log" ></param> 
        <param name="Append" value="false" /> 
        <layout class="org.apache.log4j.PatternLayout"> 
                <param name="ConversionPattern" 
                        value="%d{ISO8601} %-5p %m%n" /> 
        </layout> 
</appender> 

  
<category name="de.tai.jdtatool2"> 
        <priority value="TRACE" ></priority> 
        <appender-ref ref="jdtaconv" /> 
</category> 

</log4j:configuration>
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück