


Exemple de code Java de Log4j imprimant régulièrement des journaux et ajoutant la configuration du nom du module
Configurer l'intervalle et imprimer les journaux régulièrement
J'ai reçu une demande d'impression régulière des journaux via log4j. La demande est décrite comme suit : les journaux doivent être imprimés régulièrement et l'intervalle de temps est configurable. En parlant de timing, la première chose qui me vient à l'esprit est la classe DailyRollingFileAppender. Divers timings Selon datePattern, cela peut faire référence à la classe SimpleDateFormat. Certains paramètres de timing courants sont les suivants :
'.'yyyy-. MM : Mensuel
'.'aaaa-ww : hebdomadaire
'.'aaaa-MM-jj : quotidien
'.'aaaa-MM-jj-a : deux fois par jour
'.'aaaa-MM-jj-HH : toutes les heures
'.'aaaa-MM-jj-HH-mm : toutes les minutes
À observation, il s'avère qu'il n'existe pas de format de date de n minutes similaire, par conséquent, écrivez une classe personnalisée basée sur la classe DailyRollingFileAppender. Le processus est le suivant :
1) Copiez le code source de la classe DailyRollingFileAppender et renommez-le MinuteRollingAppender Afin de le configurer dans log4j.xml, ajoutez l'élément de configuration intervalTime et ajoutez les méthodes set et get
.private int intervalTime = 10;
2) Étant donné que la classe DailyRollingFileAppender utilise la classe RollingCalendar pour calculer le prochain intervalle de temps et que le paramètre intervalTime doit être passé, la classe RollingCalendar est modifiée en tant que classe interne depuis sa création ; La méthode consiste à calculer l'heure de la prochaine action rollOver en fonction de datePattern, cela. Il n'y a pas besoin d'autres modes de temps. La méthode de modification est la suivante :
public Date getNextCheckDate(Date now) { this.setTime(now); this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); this.add(Calendar.MINUTE, intervalTime); return getTime(); }
3) Quand. l'heure peut être configurée en fonction des minutes, le mode heure doit être désactivé, le changer en final statique et répondre Supprimer les paramètres datePattern dans ses méthodes get, set et son constructeur MinuteRollingAppender
private static String DATEPATTERN = "'.'yyyy-MM-dd-HH-mm'.log'";
De même, la méthode calculateCheckPeriod() qui sert plusieurs datePatterns peut également être supprimée ; maintenant la transformation est terminée. Les catégories de produits finis sont les suivantes :
package net.csdn.blog; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import org.apache.log4j.FileAppender; import org.apache.log4j.Layout; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; /** * 按分钟可配置定时appender * * @author coder_xia * */ public class MinuteRollingAppender extends FileAppender { /** * The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" * meaning daily rollover. */ private static String DATEPATTERN = "'.'yyyy-MM-dd-HH-mm'.log'"; /** * 间隔时间,单位:分钟 */ private int intervalTime = 10; /** * The log file will be renamed to the value of the scheduledFilename * variable when the next interval is entered. For example, if the rollover * period is one hour, the log file will be renamed to the value of * "scheduledFilename" at the beginning of the next hour. * * The precise time when a rollover occurs depends on logging activity. */ private String scheduledFilename; /** * The next time we estimate a rollover should occur. */ private long nextCheck = System.currentTimeMillis() - 1; Date now = new Date(); SimpleDateFormat sdf; RollingCalendar rc = new RollingCalendar(); /** * The default constructor does nothing. */ public MinuteRollingAppender() { } /** * Instantiate aMinuteRollingAppender
and open the file * designated byfilename
. The opened filename will become the * ouput destination for this appender. */ public MinuteRollingAppender(Layout layout, String filename) throws IOException { super(layout, filename, true); activateOptions(); } /** * @return the intervalTime */ public int getIntervalTime() { return intervalTime; } /** * @param intervalTime * the intervalTime to set */ public void setIntervalTime(int intervalTime) { this.intervalTime = intervalTime; } @Override public void activateOptions() { super.activateOptions(); if (fileName != null) { now.setTime(System.currentTimeMillis()); sdf = new SimpleDateFormat(DATEPATTERN); File file = new File(fileName); scheduledFilename = fileName + sdf.format(new Date(file.lastModified())); } else { LogLog .error("Either File or DatePattern options are not set for appender [" + name + "]."); } } /** * Rollover the current file to a new file. */ void rollOver() throws IOException { String datedFilename = fileName + sdf.format(now); // It is too early to roll over because we are still within the // bounds of the current interval. Rollover will occur once the // next interval is reached. if (scheduledFilename.equals(datedFilename)) { return; } // close current file, and rename it to datedFilename this.closeFile(); File target = new File(scheduledFilename); if (target.exists()) { target.delete(); } File file = new File(fileName); boolean result = file.renameTo(target); if (result) { LogLog.debug(fileName + " -> " + scheduledFilename); } else { LogLog.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "]."); } try { // This will also close the file. This is OK since multiple // close operations are safe. this.setFile(fileName, true, this.bufferedIO, this.bufferSize); } catch (IOException e) { errorHandler.error("setFile(" + fileName + ", true) call failed."); } scheduledFilename = datedFilename; } /** * This method differentiates MinuteRollingAppender from its super class. * ** Before actually logging, this method will check whether it is time to do * a rollover. If it is, it will schedule the next rollover time and then * rollover. * */ @Override protected void subAppend(LoggingEvent event) { long n = System.currentTimeMillis(); if (n >= nextCheck) { now.setTime(n); nextCheck = rc.getNextCheckMillis(now); try { rollOver(); } catch (IOException ioe) { if (ioe instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } LogLog.error("rollOver() failed.", ioe); } } super.subAppend(event); } /** * RollingCalendar is a helper class to MinuteRollingAppender. Given a * periodicity type and the current time, it computes the start of the next * interval. * */ class RollingCalendar extends GregorianCalendar { private static final long serialVersionUID = -3560331770601814177L; RollingCalendar() { super(); } public long getNextCheckMillis(Date now) { return getNextCheckDate(now).getTime(); } public Date getNextCheckDate(Date now) { this.setTime(now); this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); this.add(Calendar.MINUTE, intervalTime); return getTime(); } } }
La configuration du test Le fichier est le suivant :
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="myFile" class="net.csdn.blog.MinuteRollingAppender"> <param name="File" value="log4jTest.log" /> <param name="Append" value="true" /> <param name="intervalTime" value="2"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%p %d (%c:%L)- %m%n" /> </layout> </appender> <root> <priority value="debug"/> <appender-ref ref="myFile"/> </root> </log4j:configuration>
À propos de l'implémentation du timing, vous pouvez également utiliser le Timer fourni par Java pour l'implémenter, ce qui élimine le besoin de calculer et comparez l'heure à chaque fois que vous enregistrez le journal. La différence est en fait de démarrer votre propre fil de discussion et d'appeler la méthode rollOver. L'implémentation est la suivante :
package net.csdn.blog; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; import org.apache.log4j.FileAppender; import org.apache.log4j.Layout; import org.apache.log4j.helpers.LogLog; public class TimerTaskRollingAppender extends FileAppender { /** * The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" * meaning daily rollover. */ private static final String DATEPATTERN = "'.'yyyy-MM-dd-HH-mm'.log'"; /** * 间隔时间,单位:分钟 */ private int intervalTime = 10; SimpleDateFormat sdf = new SimpleDateFormat(DATEPATTERN); /** * The default constructor does nothing. */ public TimerTaskRollingAppender() { } /** * Instantiate a <code>TimerTaskRollingAppender</code> and open the file * designated by <code>filename</code>. The opened filename will become the * ouput destination for this appender. */ public TimerTaskRollingAppender(Layout layout, String filename) throws IOException { super(layout, filename, true); activateOptions(); } /** * @return the intervalTime */ public int getIntervalTime() { return intervalTime; } /** * @param intervalTime * the intervalTime to set */ public void setIntervalTime(int intervalTime) { this.intervalTime = intervalTime; } @Override public void activateOptions() { super.activateOptions(); Timer timer = new Timer(); timer.schedule(new LogTimerTask(), 1000, intervalTime * 60000); } class LogTimerTask extends TimerTask { @Override public void run() { String datedFilename = fileName + sdf.format(new Date()); closeFile(); File target = new File(datedFilename); if (target.exists()) target.delete(); File file = new File(fileName); boolean result = file.renameTo(target); if (result) LogLog.debug(fileName + " -> " + datedFilename); else LogLog.error("Failed to rename [" + fileName + "] to [" + datedFilename + "]."); try { setFile(fileName, true, bufferedIO, bufferSize); } catch (IOException e) { errorHandler.error("setFile(" + fileName + ", true) call failed."); } } } }
Cependant, il y en a deux. problèmes avec l'implémentation ci-dessus :
1) Concurrence
Un endroit où des problèmes de concurrence peuvent survenir est après avoir appelé closeFile(); le fichier est fermé à ce moment, l'erreur suivante sera signalée :
java.io.IOException: Stream closed at sun.nio.cs.StreamEncoder.ensureOpen(Unknown Source) at sun.nio.cs.StreamEncoder.write(Unknown Source) at sun.nio.cs.StreamEncoder.write(Unknown Source) at java.io.OutputStreamWriter.write(Unknown Source) at java.io.Writer.write(Unknown Source) ..............................
La solution est relativement simple, il suffit de rendre toute la méthode run() synchrone, d'ajouter Il suffit d'ajouter le mot-clé synchronisé ; cependant, l'auteur n'a actuellement pas résolu la situation où le journal peut être perdu si vous voulez vraiment écrire et que la vitesse d'écriture est suffisamment rapide
2) Performances
L'utilisation de Timer est relativement simple ; à implémenter.Cependant, si le temps d'exécution de la tâche dans Timer est trop long, cela monopolisera l'objet Timer, rendant les tâches suivantes incapables d'être exécutées. La solution est relativement simple. Utilisez la version pool de threads de la classe timer ScheduledExecutorService, qui s'implémente comme suit :
/** * */ package net.csdn.blog; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.log4j.FileAppender; import org.apache.log4j.Layout; import org.apache.log4j.helpers.LogLog; /** * @author coder_xia * <p> * 采用ScheduledExecutorService实现定时配置打印日志 * <p> * */ public class ScheduledExecutorServiceAppender extends FileAppender { /** * The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" * meaning daily rollover. */ private static final String DATEPATTERN = "'.'yyyy-MM-dd-HH-mm'.log'"; /** * 间隔时间,单位:分钟 */ private int intervalTime = 10; SimpleDateFormat sdf = new SimpleDateFormat(DATEPATTERN); /** * The default constructor does nothing. */ public ScheduledExecutorServiceAppender() { } /** * Instantiate a <code>ScheduledExecutorServiceAppender</code> and open the * file designated by <code>filename</code>. The opened filename will become * the ouput destination for this appender. */ public ScheduledExecutorServiceAppender(Layout layout, String filename) throws IOException { super(layout, filename, true); activateOptions(); } /** * @return the intervalTime */ public int getIntervalTime() { return intervalTime; } /** * @param intervalTime * the intervalTime to set */ public void setIntervalTime(int intervalTime) { this.intervalTime = intervalTime; } @Override public void activateOptions() { super.activateOptions(); Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate( new LogTimerTask(), 1, intervalTime * 60000, TimeUnit.MILLISECONDS); } class LogTimerTask implements Runnable { @Override public void run() { String datedFilename = fileName + sdf.format(new Date()); closeFile(); File target = new File(datedFilename); if (target.exists()) target.delete(); File file = new File(fileName); boolean result = file.renameTo(target); if (result) LogLog.debug(fileName + " -> " + datedFilename); else LogLog.error("Failed to rename [" + fileName + "] to [" + datedFilename + "]."); try { setFile(fileName, true, bufferedIO, bufferSize); } catch (IOException e) { errorHandler.error("setFile(" + fileName + ", true) call failed."); } } } }
Concernant la mise en place du timing, c'est presque tout. La valeur par défaut est de générer un nouveau fichier log chaque. 10 minutes. Vous pouvez le définir vous-même lors de la configuration, mais il existe un danger caché. Si la personne qui configure ne connaît pas l'intervalle de temps, si elle pense qu'il s'agit de secondes, elle en alloue 600 et active le débogage, générant un journal. fichier de taille G, ce sera certainement un désastre. La modification suivante consiste à combiner RollingFileAppender La taille maximale et le nombre maximum de fichiers de sauvegarde peuvent être configurés. Améliorez-le à nouveau et continuez à décrire le processus de transformation la prochaine fois.
Ajouter la configuration du nom du module
Comme mentionné précédemment, nous avons parlé de l'implémentation de la classe personnalisée de l'impression programmée log4j. Nous ne parlerons pas de la spécification de la taille et du nombre de fichiers de sauvegarde. Nous copions le code du. RollingFileAppender et ajoutez-le à la classe personnalisée précédente. C'est tout. La seule chose qui doit être résolue est le problème de concurrence, c'est-à-dire que lorsque le fichier est fermé et que le fichier renommé est fermé, et qu'un événement de journal se produit, une sortie. Une erreur de fermeture du flux sera signalée.
Il existe désormais un tel scénario d'application, et cela arrive souvent :
1. Le projet contient plusieurs projets différents
2. Le même projet contient différents modules ;
Pour le premier cas, vous pouvez configurer log4j
Logger logger=Logger.getLogger("Test");
Pour le deuxième cas, nous espérons pouvoir imprimer différents modules dans le même fichier journal, mais nous espérons pouvoir imprimer le nom du module dans le journal afin de pouvoir localiser le problème en cas de problème. Par conséquent, nous devons ajouter la configuration dans la classe Appender requise pour cet article, commençons la transformation. Contrairement à l'impression planifiée, nous utilisons la classe RollingFileAppender comme classe de base pour la transformation.
Tout d'abord, ajoutez l'élément de configuration moduleName et ajoutez les méthodes get et set
Puisqu'il est hérité de RollingFileAppender, il vous suffit de formater les données dans LoggingEvent dans subAppend() et d'ajouter le formatInfo méthode format Les données sont transformées, le code est omis
La catégorie du produit final est la suivante :
package net.csdn.blog; import org.apache.log4j.Category; import org.apache.log4j.RollingFileAppender; import org.apache.log4j.spi.LoggingEvent; /** * @author coder_xia * */ public class ModuleAppender extends RollingFileAppender { private String moduleName; /** * @return the moduleName */ public String getModuleName() { return moduleName; } /** * @param moduleName * the moduleName to set */ public void setModuleName(String moduleName) { this.moduleName = moduleName; } /** * 格式化打印内容 * * @param event * event * @return msg */ private String formatInfo(LoggingEvent event) { StringBuilder sb = new StringBuilder(); if (moduleName != null) { sb.append(moduleName).append("|"); sb.append(event.getMessage()); } return sb.toString(); } @Override public void subAppend(LoggingEvent event) { String msg = formatInfo(event); super.subAppend(new LoggingEvent(Category.class.getName(), event .getLogger(), event.getLevel(), msg, null)); } }
Pour plus d'exemples de code Java d'impression programmée de journaux Log4j et d'ajout de configuration de nom de module, veuillez faire attention au site Web PHP chinois !

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Cet article analyse les quatre premiers cadres JavaScript (React, Angular, Vue, Svelte) en 2025, en comparant leurs performances, leur évolutivité et leurs perspectives d'avenir. Alors que tous restent dominants en raison de fortes communautés et écosystèmes, leur populaire relatif

Cet article aborde la vulnérabilité CVE-2022-1471 dans SnakeyAml, un défaut critique permettant l'exécution du code distant. Il détaille comment la mise à niveau des applications de démarrage de printemps vers SnakeyAml 1.33 ou ultérieurement atténue ce risque, en soulignant cette mise à jour de dépendance

Le chargement de classe de Java implique le chargement, la liaison et l'initialisation des classes à l'aide d'un système hiérarchique avec Bootstrap, Extension et Application Classloaders. Le modèle de délégation parent garantit que les classes de base sont chargées en premier, affectant la classe de classe personnalisée LOA

L'article examine la mise en œuvre de la mise en cache à plusieurs niveaux en Java à l'aide de la caféine et du cache de goyave pour améliorer les performances de l'application. Il couvre les avantages de configuration, d'intégration et de performance, ainsi que la gestion de la politique de configuration et d'expulsion le meilleur PRA

Node.js 20 améliore considérablement les performances via des améliorations du moteur V8, notamment la collecte des ordures et les E / S plus rapides. Les nouvelles fonctionnalités incluent une meilleure prise en charge de Webassembly et des outils de débogage raffinés, augmentant la productivité des développeurs et la vitesse d'application.

Iceberg, un format de table ouverte pour les grands ensembles de données analytiques, améliore les performances et l'évolutivité du lac Data. Il aborde les limites du parquet / orc par le biais de la gestion interne des métadonnées, permettant une évolution efficace du schéma, un voyage dans le temps, un W simultanément

Cet article explore les méthodes de partage des données entre les étapes du concombre, la comparaison du contexte de scénario, les variables globales, le passage des arguments et les structures de données. Il met l'accent

Cet article explore l'intégration de la programmation fonctionnelle dans Java à l'aide d'expressions Lambda, de flux API, de références de méthode et facultatif. Il met en évidence des avantages tels que l'amélioration de la lisibilité au code et de la maintenabilité grâce à la concision et à l'immuabilité
