java file - Logback Appender Pfad programmgesteuert festlegen




pattern level (4)

Mit Blick auf den Logback-Code habe ich eine Umgehungslösung gefunden:

rollingPolicy.stop();
rfappender.stop();
rollingPolicy.start();
rfappender.start();

Dies führt dazu, dass Logback die neuen Definitionen verwendet. Es fühlt sich jedoch immer noch wie ein Workaround an.

Ich versuche, Logback appender Pfad programmgesteuert festzulegen. ( RollingFileAppender mit FixedWindowRollingPolicy um genau zu sein)

Ich mache das, weil ich meinen Benutzern ermöglichen möchte, den Protokollpfad in einem Einstellungsdialog (Eclipse RCP) zu setzen

Ich habe so etwas versucht, aber ich ändere den Protokollpfad nicht von dem, was in der Konfigurationsdatei definiert ist:

Logger logback_logger = (ch.qos.logback.classic.Logger)LoggerFactory
   .getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
RollingFileAppender<ILoggingEvent> rfappender = 
   (RollingFileAppender<ILoggingEvent>)logback_logger.getAppender("FILE");
rfappender.setFile(newFile);
FixedWindowRollingPolicy rollingPolicy = 
   (FixedWindowRollingPolicy)rfappender.getRollingPolicy();
rollingPolicy.setFileNamePattern(newPattern);

Nachdem Sie Ihren Appender programmgesteuert konfiguriert haben, müssen Sie seine start() -Methode aufrufen. Wenn der Appender Unterkomponenten hat, rufen Sie zuerst start() für die Unterkomponenten auf. Sie fügen dann den Appender dem Logger Ihrer Wahl hinzu.

Hier ist ein Beispiel:

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.util.StatusPrinter;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;

public class Main {
  public static void main(String[] args) {
    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();

    RollingFileAppender rfAppender = new RollingFileAppender();
    rfAppender.setContext(loggerContext);
    rfAppender.setFile("testFile.log");
    FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
    rollingPolicy.setContext(loggerContext);
    // rolling policies need to know their parent
    // it's one of the rare cases, where a sub-component knows about its parent
    rollingPolicy.setParent(rfAppender);
    rollingPolicy.setFileNamePattern("testFile.%i.log.zip");
    rollingPolicy.start();

    SizeBasedTriggeringPolicy triggeringPolicy = new ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy();
    triggeringPolicy.setMaxFileSize("5MB");
    triggeringPolicy.start();

    PatternLayoutEncoder encoder = new PatternLayoutEncoder();
    encoder.setContext(loggerContext);
    encoder.setPattern("%-4relative [%thread] %-5level %logger{35} - %msg%n");
    encoder.start();

    rfAppender.setEncoder(encoder);
    rfAppender.setRollingPolicy(rollingPolicy);
    rfAppender.setTriggeringPolicy(triggeringPolicy);

    rfAppender.start();

    // attach the rolling file appender to the logger of your choice
    Logger logbackLogger = loggerContext.getLogger("Main");
    logbackLogger.addAppender(rfAppender);

    // OPTIONAL: print logback internal status messages
    StatusPrinter.print(loggerContext);

    // log something
    logbackLogger.debug("hello");
  }
}

Der obige Code ist der programmatische Ausdruck der Schritte, die der XML-Konfigurator des Logbacks, z. B. Joran, beim Parsen der Datei RollingFixedWindow.xml ausführt .


Die Verwendung der Systemeigenschaften und das erneute Laden der Konfigurationsdatei scheint sauberer zu sein:

Ändern Sie die logback.xml-Datei:

<file>${log_path:-}myfile.log</file>
....
<FileNamePattern>${log_path:-}myfile.%i.log</FileNamePattern>

Dadurch wird der Standardspeicherort für das Arbeitsverzeichnis festgelegt. Dann benutze:

System.setProperty("log_path", my_log_path);

//Reload:
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
ContextInitializer ci = new ContextInitializer(lc);
lc.reset();
try {
  //I prefer autoConfig() over JoranConfigurator.doConfigure() so I wouldn't need to find the file myself.
  ci.autoConfig(); 
} catch (JoranException e) {
  // StatusPrinter will try to log this
  e.printStackTrace();
}
StatusPrinter.printInCaseOfErrorsOrWarnings(lc);

Gibt es im Javadoc keine Nebenwirkungen, dh mehr oder weniger Optimierung durch den JIT-Compiler?

Ich weiß nichts über die JIT-Ebene, aber es gibt direkte Bytecode-Unterstützung für den String-Pool , die magisch und effizient mit einer dedizierten CONSTANT_String_info Struktur implementiert wird (im Gegensatz zu den meisten anderen Objekten, die allgemeinere Darstellungen haben).

JVMS

JVMS 7 5.1 sagt :

Ein String-Literal ist eine Referenz auf eine Instanz der Klasse String und wird von einer CONSTANT_String_info-Struktur (§4.4.3) in der Binärdarstellung einer Klasse oder Schnittstelle abgeleitet. Die CONSTANT_String_info-Struktur gibt die Sequenz von Unicode-Codepunkten an, die das Zeichenfolgenliteral bilden.

Die Java-Programmiersprache erfordert, dass identische String-Literale (dh Literale, die dieselbe Sequenz von Codepunkten enthalten) auf dieselbe Instanz der Klasse String verweisen müssen (JLS §3.10.5). Wenn die Methode String.intern für eine beliebige Zeichenfolge aufgerufen wird, ist das Ergebnis außerdem eine Referenz auf dieselbe Klasseninstanz, die zurückgegeben würde, wenn diese Zeichenfolge als Literal angezeigt würde. Daher muss der folgende Ausdruck den Wert true haben:

("a" + "b" + "c").intern() == "abc"

Um ein String-Literal abzuleiten, untersucht die Java Virtual Machine die Reihenfolge der Codepunkte, die von der CONSTANT_String_info-Struktur angegeben werden.

  • Wenn die Methode String.intern zuvor für eine Instanz der Klasse String aufgerufen wurde, die eine Sequenz von Unicode-Codepunkten enthält, die identisch mit der Struktur CONSTANT_String_info ist, ist das Ergebnis der String-Literalableitung eine Referenz auf dieselbe Instanz der Klasse String.

  • Andernfalls wird eine neue Instanz der Klasse String erstellt, die die von der CONSTANT_String_info-Struktur angegebene Sequenz von Unicode-Codepunkten enthält. Ein Verweis auf diese Klasseninstanz ist das Ergebnis der String-Literal-Ableitung. Abschließend wird die interne Methode der neuen String-Instanz aufgerufen.

Bytecode

Es ist auch lehrreich, die Bytecode-Implementierung auf OpenJDK 7 zu betrachten.

Wenn wir dekompilieren:

public class StringPool {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == c);
    }
}

Wir haben auf dem konstanten Pool:

#2 = String             #32   // abc
[...]
#32 = Utf8               abc

und main :

 0: ldc           #2          // String abc
 2: astore_1
 3: ldc           #2          // String abc
 5: astore_2
 6: new           #3          // class java/lang/String
 9: dup
10: ldc           #2          // String abc
12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne     42
38: iconst_1
39: goto          43
42: iconst_0
43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V

Beachten Sie, wie:

  • 0 und 3 : die gleiche ldc #2 Konstante ist geladen (die Literale)
  • 12 : Eine neue String-Instanz wird erstellt (mit #2 als Argument)
  • 35 : a und c werden als reguläre Objekte mit if_acmpne

Die Darstellung von konstanten Strings ist ziemlich magisch auf dem Bytecode:

  • Es hat eine dedizierte CONSTANT_String_info Struktur, im Gegensatz zu regulären Objekten (zB new String )
  • Die Struktur verweist auf eine CONSTANT_Utf8_info-Struktur , die die Daten enthält. Das sind die einzigen notwendigen Daten, um die Zeichenkette darzustellen.

und das obige JVMS-Zitat scheint zu sagen, dass immer, wenn Utf8 auf dasselbe zeigt, identische Instanzen von ldc geladen werden.

Ich habe ähnliche Tests für Felder durchgeführt und:

Bonus : Vergleichen Sie das mit dem Integer-Pool , der keine direkte Bytecode-Unterstützung hat (dh kein CONSTANT_String_info Analog).







java logging logback