web-dev-qa-db-fra.com

Comment faire pour rouler le fichier journal au démarrage dans la journalisation

Je voudrais configurer la consignation pour faire ce qui suit.

  • Se connecter à un fichier
  • Faites rouler le fichier quand il atteint 50 Mo
  • Ne gardez que 7 jours de bûches
  • Au démarrage, générez toujours un nouveau fichier (faites un rouleau)

Tout fonctionne sauf le dernier élément, le rouleau de démarrage. Est-ce que quelqu'un sait comment y parvenir? Voici la config ...

  <appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender">

    <layout class="ch.qos.logback.classic.PatternLayout">
      <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg \(%file:%line\)%n</Pattern>
    </layout>

    <File>server.log</File>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <FileNamePattern>server.%d{yyyy-MM-dd}.log</FileNamePattern>
      <!-- keep 7 days' worth of history -->
      <MaxHistory>7</MaxHistory>

      <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <MaxFileSize>50MB</MaxFileSize>
      </TimeBasedFileNamingAndTriggeringPolicy>

    </rollingPolicy>
  </appender>
42
Mike Q

Aucune des autres suggestions ne convenait à ma situation. Je ne voulais pas utiliser une solution basée sur la taille et le temps, car elle nécessite la configuration d'un fichier MaxFileSize et nous utilisons une stratégie strictement basée sur le temps. Voici comment j'ai réussi à faire rouler le fichier au démarrage avec TimeBasedRollingPolicy:

@NoAutoStart
public class StartupTimeBasedTriggeringPolicy<E> 
        extends DefaultTimeBasedFileNamingAndTriggeringPolicy<E> {

    @Override
    public void start() {
        super.start();
        nextCheck = 0L;
        isTriggeringEvent(null, null);
        try {
            tbrp.rollover();
        } catch (RolloverFailure e) {
            //Do nothing
        }
    }

}

L'astuce consiste à définir l'heure nextCheck sur 0L pour que isTriggeringEvent () pense qu'il est temps de déplacer le fichier journal. Il exécutera ainsi le code nécessaire au calcul du nom de fichier, ainsi qu’à la réinitialisation pratique de la valeur de l’heure nextCheck. L'appel ultérieur à rollover () provoque le roll du fichier journal. Comme cela ne se produit qu'au démarrage, il s'agit d'une solution plus optimale que celles qui effectuent une comparaison dans isTriggerEvent (). Si petite que soit cette comparaison, elle réduit encore légèrement les performances lorsqu'elle est exécutée sur tous les messages du journal. Cela force également le basculement à se produire immédiatement au démarrage, au lieu d'attendre le premier événement de journal.

L'annotation @NoAutoStart est importante pour empêcher Joran d'exécuter la méthode start () avant la fin de toutes les autres initialisations. Sinon, vous obtenez une exception NullPointerException.

Voici la config:

  <!-- Daily rollover appender that also appends timestamp and rolls over on startup -->
  <appender name="startupDailyRolloverAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_FILE}</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_FILE}.%d{yyyyMMdd}_%d{HHmmss,aux}</fileNamePattern>
      <TimeBasedFileNamingAndTriggeringPolicy class="my.package.StartupTimeBasedTriggeringPolicy" />
    </rollingPolicy>
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender> 

J'espère que cela t'aides!

25
Dave

Cela fonctionne pour moi, en utilisant la classe suivante comme timeBasedFileNamingAndTriggeringPolicy:

import Java.io.File;
import Java.util.concurrent.atomic.AtomicBoolean;

import ch.qos.logback.core.joran.spi.NoAutoStart;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;

@NoAutoStart
public class Trigger<E> extends SizeAndTimeBasedFNATP<E>
{
    private final AtomicBoolean trigger = new AtomicBoolean();

    public boolean isTriggeringEvent(final File activeFile, final E event) {
        if (trigger.compareAndSet(false, true) && activeFile.length() > 0) {
            String maxFileSize = getMaxFileSize();
            setMaxFileSize("1");
            super.isTriggeringEvent(activeFile, event);
            setMaxFileSize(maxFileSize);
            return true;
        }
        return super.isTriggeringEvent(activeFile, event);
    }
}
7
proactif

Pour une solution utilisant des composants déjà existants, la consignation suggère le fichiers portant un nom unique: http://logback.qos.ch/manual/appenders.html#uniquelyNamed

Au cours de la phase de développement de l'application ou dans le cas d'une courte durée de vie applications, par exemple applications par lots, il est souhaitable de créer un nouveau fichier journal à chaque nouveau lancement d’application. C'est assez facile à faire à l'aide de l'élément <timestamp>.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <timestamp key="startTimestamp" datePattern="yyyyMMddHHmmssSSS"/>
    <appender name="File"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg \(%file:%line\)%n</Pattern>
        </layout>

        <file>server-${startTimestamp}.log</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>server-${startTimestamp}-%d{yyyy-MM-dd}-%i.log</FileNamePattern>
            <!-- keep 7 days' worth of history -->
            <MaxHistory>7</MaxHistory>

            <TimeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <MaxFileSize>1KB</MaxFileSize>
            </TimeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="File" />
    </root>
</configuration>

UPDATED pour logback-1.2.1

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <timestamp key="startTimestamp" datePattern="yyyyMMddHHmmssSSS"/>
    <appender name="File"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg \(%file:%line\)%n</Pattern>
        </layout>

        <file>server-${startTimestamp}.log</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>server-${startTimestamp}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <!-- keep 7 days' worth of history -->
            <maxHistory>7</maxHistory>
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="File" />
    </root>
</configuration>
5
raisercostin

J'ai trouvé une autre solution pour lancer le fichier journal une fois, lorsque l'application démarre. 

J'utilise la variable RollingFileAppender de logback avec la variable FixedWindowRollingPolicy de logback et ma propre implémentation d'un TriggeringPolicy<E>.

La FixedWindowRollingPolicy obtient le fileNamePattern pour le nouveau fichier journal, où %1 est le nouveau numéro du fichier. MaxIndex représente le nombre maximum de mon "historique". Plus d'informations: FixedWindowRollingPolicy

Mes implémentations TriggeringPolicy retournent true pour la première fois, lorsque isTriggeringEvent (...) est appelé. Ainsi, WindowRollingPolicy survole les fichiers journaux, lorsque la stratégie est appelée pour la première fois, et ensuite, elle ne sera pas annulée.

La configuration xml pour la RollingFileAppender:

<configuration>
    ...
    <appender name="FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logFile.log</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>logFile.%i.log</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>4</maxIndex>
        </rollingPolicy>

        <triggeringPolicy class="my.classpath.RollOncePerSessionTriggeringPolicy"/>
    </appender>
...
</configuration>

La TriggeringPolicy:

package my.classpath;

import ch.qos.logback.core.rolling.TriggeringPolicyBase;

import Java.io.File;

public class RollOncePerSessionTriggeringPolicy<E> extends TriggeringPolicyBase<E> {
    private static boolean doRolling = true;

    @Override
    public boolean isTriggeringEvent(File activeFile, E event) {
        // roll the first time when the event gets called
        if (doRolling) {
            doRolling = false;
            return true;
        }
        return false;
    }
}
5
duffy356

Remplacer la méthode isTriggeringEvent () dans ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP devrait fonctionner correctement. Il suffit de renvoyer 'true' la première fois que la méthode isTriggeringEvent () est appelée.

3
Ceki

La solution de Ceki ne semble pas fonctionner pour moi, mais semble être au moins à mi-chemin.

Il explose car il ne peut pas voir la stratégie évolutive au démarrage de TimeBasedFileNamingAndTriggeringPolicyBase. Avec un peu de hackery, je devais faire une journalisation, et avec un peu plus, je devais observer le déclencheur, mais ensuite il s'est cassé à nouveau parce qu'il ne pouvait pas résoudre une des propriétés du nom de fichier ... Le paquet est un pourrait accéder à certains éléments internes, pour reproduire une partie de la logique dans SizeAndTimeBasedFNATP#isTriggeringEvent et appeler computeCurrentPeriodsHighestCounterValue. Je pense que quelque chose dans ce sens pourrait fonctionner, je n'ai pas encore trouvé la combinaison magique. J'espère vraiment que je vais faire quelque chose de stupide, parce que sinon, je pense que cela signifiera soit d'ouvrir certains détails pour le sous-classement, soit de mettre cela directement dans le logback comme une autre politique évolutive/déclenchante.

logback.xml: essayé divers ordres de triggeringPolicy, TimeBasedFileNamingAndTriggeringPolicy à l'intérieur et à l'extérieur de rollingPolicy.

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_DIR}/${LOG_FILE_BASE}.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${LOG_DIR}/${LOG_FILE_BASE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <MaxHistory>7</MaxHistory>

        <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.RollOnStartupPolicy" />
    </rollingPolicy>

    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>INFO</level>
    </filter>

    <encoder>
        <pattern>%msg%n</pattern>
    </encoder>
</appender>

La politique de déclenchement:

package ch.qos.logback.core.rolling;
public class RollOnStartupPolicy<E> extends SizeAndTimeBasedFNATP<E> {
private final AtomicBoolean firstTime = new AtomicBoolean(true);

    @Override
    public boolean isTriggeringEvent(File activeFile, E event) {
        if (!firstTime.get()) { // fast path
            return false;
        }

        if (firstTime.getAndSet(false)) {
            return true;
        }
        return false;
    }
}

L'éxéption:

Java.lang.NullPointerException
at  at ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicyBase.start(TimeBasedFileNamingAndTriggeringPolicyBase.Java:46)
at  at ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP.start(SizeAndTimeBasedFNATP.Java:36)
at  at ch.qos.logback.core.joran... [snip joran config]
2
Joe Kearney

Cette solution fonctionne vraiment, merci beaucoup . Cependant, il y a un petit problème gênant: lorsque vous exécutez le programme pour la première fois, le journal est lancé juste après sa création, qu'il soit vide ou presque vide . Je suggère un correctif: vérifiez si le fichier journal existe et s'il n'est pas vide au moment où la méthode s'appelle . De plus, un correctif esthétique supplémentaire: renommez la variable "démarré", car elle masque le membre hérité avec le même prénom.

@NoAutoStart
public class StartupSizeTimeBasedTriggeringPolicy<E> extends     SizeAndTimeBasedFNATP<E> {

    private boolean policyStarted;

    @Override
    public boolean isTriggeringEvent(File activeFile, E event) {
        if (!policyStarted) {
            policyStarted = true;
            if (activeFile.exists() && activeFile.length() > 0) {
                nextCheck = 0L;
                return true;
            }
        }
        return super.isTriggeringEvent(activeFile, event);
    }
}

De plus, je pense que cela fonctionne correctement avec logback version 1.1.4-SNAPSHOT (le code source a été compilé moi-même), mais cela ne fonctionne pas complètement avec la version 1.1.3. Avec 1.1.3, il nomme les fichiers correctement avec le fuseau horaire spécifié, mais le basculement a toujours lieu au fuseau horaire par défaut, minuit.

1
Leonid Ilyevsky

J'ai eu ce qui suit au travail (en combinant les idées des réponses précédentes). Remarque: je traitais avec des fichiers basés sur la taille, pas sur le temps, mais je suppose que la même solution fonctionne.

public class StartupSizeBasedTriggeringPolicy<E> extends ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy<E> {

private final AtomicReference<Boolean> isFirstTime = new AtomicReference<Boolean>(true);

@Override
public boolean isTriggeringEvent(final File activeFile, final E event) {

    //this method appears to have side-effects so always call
    boolean result = super.isTriggeringEvent(activeFile, event);

    return isFirstTime.compareAndSet(true, false) || result;
}

}

1
djechlin

Créez votre propre sous-classe de ch.qos.logback.core.rolling.TimeBasedRollingPolicy et remplacez sa start

public class MyPolicy
    extends ch.qos.logback.core.rolling.TimeBasedRollingPolicy
{

    public void start ( )
    {
        super.start( );
        rollover( );
    }
}
1

J'ai finalement compris. Je peux rouler par taille, heure et démarrage. Voici la solution:

1er créer votre propre classe

@NoAutoStart
public class StartupSizeTimeBasedTriggeringPolicy<E> extends SizeAndTimeBasedFNATP<E> {

    private boolean started = false;

    @Override
    public boolean isTriggeringEvent( File activeFile, E event ) {
        if ( !started ) {
            nextCheck = 0L;
            return started = true;
        }

        return super.isTriggeringEvent( activeFile, event );
    };
}

2ème configurer la connexion

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOGS_DIR}/${FILE_NAME}.log</file>
    <encoder>
        <pattern>%d [%thread] %-5level %logger{50} - %msg%n</pattern>
    </encoder>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${LOGS_DIR}/${FILE_NAME}.%d{yyyy-MM-dd}_%d{HHmmss,aux}.%i.log.Zip</fileNamePattern>
        <maxHistory>30</maxHistory>
        <TimeBasedFileNamingAndTriggeringPolicy class="my.StartupSizeTimeBasedTriggeringPolicy">
            <MaxFileSize>250MB</MaxFileSize> 
        </TimeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
</appender>
1
Perlos

L'API a changé (par exemple, setMaxFileSize n'existe plus) et beaucoup de choses ci-dessus ne semblent pas fonctionner, mais j'ai quelque chose qui fonctionne pour moi contre logback 1.1.8 (le plus récent pour l'instant).

Je voulais rouler au démarrage et rouler sur la taille, mais pas le temps. Cela le fait:

public class RollOnStartupAndSizeTriggeringPolicy<E> extends SizeBasedTriggeringPolicy<E> {
    private final AtomicBoolean firstTime = new AtomicBoolean();

    public boolean isTriggeringEvent(final File activeFile, final E event) {
        if (firstTime.compareAndSet(false, true) && activeFile != null && activeFile.length() > 0) {
            return true;
        }
        return super.isTriggeringEvent(activeFile, event);
    }
}

Avec cela, vous avez également besoin d'une politique évolutive. FixedWindowRollingPolicy ferait probablement l'affaire, mais je n'aime pas cela parce que je veux conserver un grand nombre de fichiers, ce qui est très inefficace pour cela. Quelque chose qui augmente progressivement (au lieu de glisser comme FixedWindow) fonctionnerait, mais cela n’existe pas. Tant que j'écris moi-même, j'ai décidé d'utiliser le temps au lieu de compter. Je voulais étendre le code de consignation actuel, mais pour les tâches basées sur le temps, les stratégies de roulement et de déclenchement sont souvent combinées en une seule classe. J'ai donc dû faire beaucoup à partir de zéro. Je reste simple et je n’ai pas implémenté de fonctionnalités telles que la compression. J’adorerais les utiliser, mais j’essaie simplement de garder les choses simples.

public class TimestampRollingPolicy<E> extends RollingPolicyBase {
    private final RenameUtil renameUtil = new RenameUtil();
    private String activeFileName;
    private String fileNamePatternStr;
    private FileNamePattern fileNamePattern;

    @Override
    public void start() {
        super.start();
        renameUtil.setContext(this.context);
        activeFileName = getParentsRawFileProperty();
        if (activeFileName == null || activeFileName.isEmpty()) {
            addError("No file set on appender");
        }
        if (fileNamePatternStr == null || fileNamePatternStr.isEmpty()) {
            addError("fileNamePattern not set");
            fileNamePattern = null;
        } else {
            fileNamePattern = new FileNamePattern(fileNamePatternStr, this.context);
        }
        addInfo("Will use the pattern " + fileNamePattern + " to archive files");
    }

    @Override
    public void rollover() throws RolloverFailure {
        File f = new File(activeFileName);
        if (!f.exists()) {
            return;
        }
        if (f.length() <= 0) {
            return;
        }
        try {
            String archiveFileName = fileNamePattern.convert(new Date(f.lastModified()));
            renameUtil.rename(activeFileName, archiveFileName);
        } catch (RolloverFailure e) {
            throw e;
        } catch (Exception e) {
            throw new RolloverFailure(e.toString(), e);
        }
    }

    @Override
    public String getActiveFileName() {
        return activeFileName;
    }

    public void setFileNamePattern(String fnp) {
        fileNamePatternStr = fnp;
    }
}

Et puis config ressemble

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
  </encoder>
  <file>/tmp/monitor.log</file>
  <rollingPolicy class="my.log.TimestampRollingPolicy">
    <fileNamePattern>/tmp/monitor.%d{yyyyMMdd-HHmmss}.log</fileNamePattern>
  </rollingPolicy>
  <triggeringPolicy class="my.log.RollOnStartupAndSizeTriggeringPolicy">
    <maxFileSize>1gb</maxFileSize>
  </triggeringPolicy>
</appender>

si vous êtes frustré, cela ne résout pas votre problème de manière native, votez pour

http://jira.qos.ch/browse/LOGBACK-204

http://jira.qos.ch/browse/LOGBACK-215

(Cela fait des années, et pour moi, c'est une fonctionnalité absolument essentielle, même si je sais que de nombreux autres frameworks échouent également)

0
dlipofsky