간격 구성 및 정기적으로 로그 인쇄
log4j를 통해 로그를 정기적으로 인쇄해 달라는 요청을 받았습니다. 요청은 다음과 같습니다. 로그는 정기적으로 인쇄되어야 하며 시간 간격은 구성 가능합니다. 타이밍에 대해 말하면 가장 먼저 떠오르는 것은 DailyRollingFileAppender 클래스입니다. datePattern에 따르면 이는 SimpleDateFormat 클래스를 참조할 수 있습니다.
'.'yyyy- MM: 월별
'.'yyyy-ww: 매주
'.'yyyy-MM-dd: 매일
'.'yyyy-MM-dd-a: 하루에 두번
'.'yyyy-MM-dd-HH : 매시간
'.'yyyy-MM-dd-HH-mm : 매분
까지 관찰 결과 유사한 n분 날짜 형식이 없는 것으로 확인되었으므로 DailyRollingFileAppender 클래스를 기반으로 사용자 정의 클래스를 작성하십시오. 프로세스는 다음과 같습니다.
1) DailyRollingFileAppender 클래스 소스 코드를 복사하고 MinuteRollingAppender로 이름을 변경합니다. log4j.xml에서 구성 항목을 추가하고 set 및 get 메소드를 추가합니다.
private int intervalTime = 10;
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(); }
private static String DATEPATTERN = "'.'yyyy-MM-dd-HH-mm'.log'";
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(); } } }
<?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>
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."); } } } }
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) ..............................
2) 성능
/** * */ 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."); } } } }
앞서 log4j 예약 인쇄의 사용자 정의 클래스 구현에 대해 이야기했습니다. 우리는 RollingFileAppender 클래스에서 코드를 복사합니다. 해결해야 할 유일한 것은 동시성 문제, 즉 파일이 닫히고 이름 변경 파일이 닫히고 로그 이벤트가 발생하면 출력 스트림이 닫히는 것입니다. 오류가 보고됩니다. <…
Logger logger=Logger.getLogger("Test");
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)); } }
Log4j 예약 로그 인쇄 및 모듈 이름 구성 추가에 대한 더 많은 Java 코드 예제를 보려면 PHP 중국어 웹사이트에 주목하세요!