Logging mit log4j2 in verschiedene Dateien?

MiMa

Top Contributor
Ich setze zum logging log4j2 ein und soweit funktioniert es ganz gut.
Jedoch erhalte ich eine ziemlich lange Logdatei und mir ist der Gedanke gekommen diese Logs auf zu teilen, da ich diese an verschiedenen Stellen benötige.

Kennt jemand eine Möglichkeit, das ich ein Log erstellen kann welches den Namen der zu untersuchenden Datei erhält jedoch mit der Endung .log.
Dann würde ich aus einer anderen Klasse die Logs in eine separate Datei Speichern.

Meine Konfigurationsdatei
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%t] %-5level %logger{36} - %msg%n" />
        </Console>
        <File name="log" fileName="logs/Logger.log" immediateFlush="false" append="false">
            <PatternLayout pattern="%logger{36} - %msg%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <!-- <AppenderRef ref="Console" /> -->
            <AppenderRef ref="log"/>
        </Root>
    </Loggers>
</Configuration>

Danke
Mi
 
Ich würde einen speziellen Appender für diese Klasse konfigurieren.
Vielleicht gibts noch andere Lösungen, aber das wäre mein Ansatz
 
In den Appender sind die Namen und der Speicherort der Logdatei fest eingebunden.
Mich würde interessieren ob und wie man das dynamisch machen kann?
Der Name und Speicherort der Logdatei soll sich ständig ändern damit diese nicht überschrieben werden
 
Danke,
kann ich überhaupt einen Dateipfad die während der Laufzeit erstellt werden an eine LOG-Konfigurationsdatei übergeben?
XML:
fileName="${LOG_DIR}/application.log"
Ich weis nicht wie ich das lösen könnte.
 
Die Logdateien sollen zu den zu Überprüften Dateien geschrieben werden.
Das bedeutet, das die Zielverzeichnisse unterschiedlich sind und der Name sich auch ständig ändert.
 
Meine Konfiguration
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <File name="LogDatei" fileName="${sys:logDateiName}">
            <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="LogDatei"/>
        </Root>
    </Loggers>
</Configuration>
Java Klasse
Java:
package log4j;

import java.util.Properties;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Logging {

    public static Properties prop = new Properties(System.getProperties());
    
     // Erstellt ein LoggerObjekt
    private static Logger LOG = LogManager.getLogger(Logging.class);

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
        prop.setProperty("logDateiName", "B:\\Logging.log");
        LOG = LogManager.getLogger(Logging.class);
        
        LOG.info("Erster Informations Log");
        LOG.warn("Erster Warn Log");
    } // main
} // Logging
Fehlermeldung
Code:
2020-06-14 13:40:26,586 main ERROR FileManager (${sys:logDateiName}) java.io.IOException: Die Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnung ist falsch java.io.IOException: Die Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnung ist falsch
    at java.base/java.io.WinNTFileSystem.canonicalize0(Native Method)
 
Habe es geändert, die Fehlermeldung ist aber dennoch die gleiche?
Java:
prop.setProperty("logDateiName", "B:/Logging.log");
Das mit den vier Backslashes habe ich leider auch ohne Erfolgt auch probiert??
 
Zuletzt bearbeitet:
Ähm, du willst ein System Property Setzen? Du erstellst eine Instanz und setzt in der eine Property. Das ändert aber nicht die System Property.

Daher wird die gesetzte Property im Logger nie ankommen. System.setProperty müsste dazu aufgerufen werden.

Und ich bin mir unsicher, ob er das erst danach liest oder ob die config Datei nicht schon früher gelesen wird und ob die statische Initialisierung zu entfernen erwas bringt. Aber das wird dein Test dann ja zeigen.
 
Naja, wirklich funktioniert es nicht.
Ich habe gelesen, das die XML Konfiguration den Dateinamen aus den System Preferenzen holt
Code:
${sys:logDateiName}">
Dann muss die aber vorher dort gespeichert werden und das habe ich setProperty versucht.
Da der die Werte vor dem aufruf drin sein muss, habe ich danach den LogManager nochmal geholt.
Irgendwie scheint es aber nicht zu funktionieren???

Gibt es vielleicht noch eine andere Möglichkeit während der Laufzeit in andere Logdateien zu schreiben mit unterschiedlichen Lognamen?
 
Zuletzt bearbeitet:
Hast Du denn die Initialisierung bei der Deklaration auch raus genommen?

private static Logger LOG = LogManager.getLogger(Logging.class)

Das ist aber ggf. auch nicht ausreichend. Ich weiss nicht sicher, wann Log4j die Datei auswertet. Wenn das direkt beim Laden der Klassen passiert, dann dürfte Dein Vorhaben schwer machbar sein.

Aber ich verstehe den Usecase auch nicht wirklich. Woher kommt der Dateiname? Zur Laufzeit? Dann kannst Du den Appender ja im Config-File weg lassen und komplett in Code hinzu fügen. (https://logging.apache.org/log4j/2.x/manual/customconfig.html könnte da etwas hilfreich sein - wurde ja schon verlinkt! Wichtig ist: Du machst die Configuration dann im vor allem im Code! ).

Wenn es aus einer Konfigurationsdatei kommen soll: Dazu hast Du ja die log4j2.xml. Da kann es dann entsprechend vermerkt sein. Oder Du nutzt eigene Config-Files und machst es damit im Code (Eher schlecht - würde ich von abraten, da Du Dich damit stark einschränkst).

Sorry, wenn ich daher nicht wirklich helfen kann - aber mir war im Code halt das Setzen der Property aufgefallen, was eben keine System-Property setzt...
 
Du musst das property vor dem Start setzen mit -DlogDateiName=C:/temp/test.log während der Laufzeit funktioniert es nicht. Habe das eben getestet.

Was ich aber eigentlich gemeint habe, wäre sowas: (de.java.Logging ist meine Testklasse, für die speziell geloggt werden soll)

XML:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="STDOUT">
            <PatternLayout pattern="%C{1.} %m %level MDC%X%n"/>
        </Console>
        <File name="LogDatei" fileName="c:/temp/test.log">
            <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Logger  name="de.java.Logging" level="DEBUG">
            <AppenderRef ref="LogDatei"/>
        </Logger>
        <Root level="INFO">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>
 
Der Dateiname der Logdatei wird während der Laufzeit generiert.
So in etwa sollte es aussehen am Beispiel einer eBook-PDF Datei:
B:\Postfach\Der Java Profi.pdf -> Ursprungsdatei und wird danach verschoben nach B:\Bibliothek\Informatik\Java\DerJavaProfi.pdf
B:\Bibliothek\Informatik\Java\DerJavaProfi.log -> Logdatei
B:\Bibliothek\Informatik\Java\DerJavaProfi.xml -> Metadaten
B:\Fehlermeldungen.log -> alle Problemmeldungen
 
Alternative die mir einfallen würde, wäre das schreibe einer Textdatei an der ich die Meldungen einfach anhänge??
 
Habe das Problem gelöst indem ich mir eine eigene Logging Methode geschrieben habe, die mir je nach Art
eine eigene LOG-Datei zur Laufzeit erzeugt.
 
Ok, ich habe jetzt aber auch ein bisschen gebastelt. Irgendwie wollte er bei mir keinen neuen Logger / Appender einfügen. Aber ich habe problemlos einen existierenden Appender austauschen können.

Wieso ersteres nicht lief kann ich nicht sagen. Aber mein aktueller Zwischenstand ist dies:

Meine log4j2.xml definiert eine LogDatei. Das ist dann erst einmal mein Appender, den ich dann weiter verwenden möchte. "de.kneitzel" ist mein Package, aus dem ich logge ...
Code:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="STDOUT">
            <PatternLayout pattern="%C{1.} %level %m%n"/>
        </Console>
        <File name="LogDatei" fileName="./test.log">
            <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Logger name="de.kneitzel" level="DEBUG">
            <AppenderRef ref="LogDatei"/>
        </Logger>
        <Root level="INFO">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>

Dann meine Klasse / Testprogramm:
Java:
package de.kneitzel.test;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;

import java.io.Serializable;

public class Log4jAppenderHandler {

    private static Logger log = LogManager.getLogger(Log4jAppenderHandler.class.getName());

    private String appenderName;
    private String packageName;

    private LoggerContext context;
    private Configuration configuration;
    private Layout<? extends Serializable> layout;

    public Log4jAppenderHandler(final String appenderName, final String packageName) {
        this.appenderName = appenderName;
        this.packageName = packageName;

        context = (LoggerContext) LogManager.getContext(false);
        configuration = context.getConfiguration();
        layout = configuration.getAppender(appenderName).getLayout();
    }


    void updateLogger(final String fileName){

        //delete old appender/logger
        configuration.getAppender(appenderName).stop();
        configuration.removeLogger(packageName);

        //create new appender/logger
        LoggerConfig loggerConfig = new LoggerConfig(packageName, Level.INFO, false);
        FileAppender appender = FileAppender.newBuilder()
                .withFileName(fileName)
                .withAppend(false)
                .withLocking(false)
                .setName(appenderName)
                .withImmediateFlush(true)
                .setIgnoreExceptions(true)
                .withBufferedIo(true)
                .withBufferSize(8192)
                .setLayout(layout)
                .setFilter(null)
                .withAdvertise(false)
                .setConfiguration(configuration)
                .build();
        appender.start();
        loggerConfig.addAppender(appender, Level.INFO, null);
        configuration.addLogger(packageName, loggerConfig);

        context.updateLoggers();
    }

    public static void main(String[] args) {
        // First test message...
        log.warn("Start logging test!");

        // appenderName und packageName kommen aus log4j.xml!
        Log4jAppenderHandler log4jHandler = new Log4jAppenderHandler("LogDatei", "de.kneitzel");

        log4jHandler.updateLogger("./test1.log");
        log.warn ("After updating to test1.log!");

        log4jHandler.updateLogger("./test2.log");
        log.warn ("After updating to test2.log!");
    }

}


Bei meinem Testprogramm wird dann das Logging immer schön weiter umgeleitet.
Erst das ./test.log aus dem Config-File. Da landet dann das erste logging drin.
Dann kommt der switch zu test1.log -> und das nächste log kommt da rein.
Dann switch zu test2.log und das letzte log kommt da in die Datei.

Damit hätte man etwas Code, der zur Laufzeit ein Logfile ändern kann.
 
Danke, das du dich damit beschäftigt hast.
Ich kenne mich nicht gut genug damit aus um es so zu lösen. 🙂
Habe den ganzen Tag damit verbracht und bin da nicht weiter gekommen. Dann habe ich mit ca 10 Zeilen einen eigenen Logger geschrieben, der mir 3 verschiedene Dateien schreibt und konnte meine log4j Anweisungen sehr einfach ändern.
Auf jeden Fall schaue ich mit Deinen Code an und versuche das mal nach zu verfolgen um eine Wissenslücke zu schließen.
Eine Logdatei loggt die Anwendung, eine weitere Loggt nur die erzeugten Metadaten und die dritte Loggt alle Fehler.
Da ich mich noch nicht mit JUnit beschäftigen konnte kontrolliere ich halt die Logs.
 
@JustNobody
nochmal vielen Dank.
Ich habe deinen Lösungsweg verstanden und werde diesen in meiner Version mit Java-FX und GUI implemetieren.
Der File-Appender hat ja echt viele Parameter 😉
Mi
 

Zurück
Oben