Implementation of the log4j custom class (1): configure the interval and regularly print logs

Source: Internet
Author: User
Tags date now

When receiving a requirement, you can use log4j to print logs at regular intervals. The requirement is described as follows: You must be able to print logs at regular intervals. Speaking of timing, I first thought of the dailyrollingfileappender class and various timing. According to datepattern, refer to the simpledateformat class. Some common timing settings are as follows:

'. 'Yyyy-MM: month '. 'yyyy-ww: weekly '. 'yyyy-mm-DD: daily '. 'yyyy-mm-dd-A: Twice a day '. 'yyyy-mm-dd-hh: Hourly '. 'yyyy-mm-dd-hh-MM: minute

It is found that there is no date format similar to n minutes. Therefore, you can write custom classes based on the dailyrollingfileappender class. The process is as follows:

1) copy the dailyrollingfileappender class source code and rename it minuterollingappender. In order to configure it in log4j. XML, add the configuration item intervaltime and add the set and get methods;

private int intervalTime = 10;

2) because the dailyrollingfileappender class uses the rollingcalendar class to calculate the next interval, and the parameter intervaltime needs to be passed, the rollingcalendar class is changed to an internal class; because the method is to calculate the time of the next rolover action based on datepattern, no other time mode is required. The modification method is as follows:

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) when the configuration is available by minute, the time mode needs to be disabled. Change it to static final. Remove the get, set method, and datepattern parameters in the minuterollingappender constructor from the response.

private static String DATEPATTERN = "'.'yyyy-MM-dd-HH-mm'.log'";

Similarly, the computecheckperiod () method that serves multiple datepattern can also be deleted. Now the transformation is complete. The finished product class is as follows:

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;/*** the appender can be configured by minute ** @ Uthor coder_xia **/public class minuterollingappender extends fileappender {/*** the date pattern. by default, the pattern is set "'. 'yyyy-mm-dd "* Meaning daily rolover. */Private Static string datepattern = "'. 'yyyy-mm-dd-hh-mm '. log' ";/*** interval, in the unit of minute */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 rolover * 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 rolover occurs depends on logging activity. */private string scheduledfilename;/*** the next time we estimate a rolover shoshould 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 a <code> minuterollingappender </code> and open the file * designated by <code> filename </code>. the opened filename will become the * ouput destination for this appender. */Public minuterollingappender (layout, string filename) T Hrows 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;} @ overridepublic void activateoptions () {super. activateoptions (); If (filename! = NULL) {now. settime (system. currenttimemillis (); SDF = new simpledateformat (datepattern); 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 + "]. ") ;}}/*** rolover the current file to a new file. */void rolover () 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. rolover will occur once the // next interval is reached. if (scheduledfilename. equals (datedfilename) {return;} // close current file, and rename it to datedfilenamethis. closefile (); file target = new file (scheduledfilename); If (target. exists () {target. delete ();} 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. ** <p> * before actually logging, this method will check whether it is time to do * A rolover. if it is, it will schedule the next rolover time and then * rolover. **/@ overrideprotected void subappend (loggingevent event) {long n = system. currenttimemillis (); If (n> = nextcheck) {now. settime (n); nextcheck = RC. getnextcheckmillis (now); try {rolover ();} catch (ioexception IOE) {If (IOE instanceof interruptedioexception) {thread. currentthread (). interrupt ();} loglog. error ("rolover () 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 =-regular; 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 ();}}}

The test configuration file is as follows:

<?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>

The timing implementation can also be implemented using the timer provided by Java, which eliminates the need to calculate and compare the time each time logs are recorded. The difference is that you start a thread and call the rolover method. The implementation is as follows:

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 "'. 'yyyy-mm-dd "* Meaning daily rolover. */Private Static final string datepattern = "'. 'yyyy-mm-dd-hh-mm '. log' ";/*** interval, in the unit of minute */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, 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;} @ overridepublic void activateoptions () {super. activateoptions (); timer = new timer (); timer. schedule (New logtimertask (), 1000, intervaltime * 60000);} class logtimertask extends timertask {@ overridepublic void run () {string datedfilename = filename + SDF. format (new date (); closefile (); file target = new file (datedfilename); If (target. exists () target. delete (); file = new file (filename); boolean result = file. renameto (target); If (result) loglog. debug (filename + "->" + datedfilename); elseloglog. error ("failed to rename [" + filename + "] to [" + datedfilename + "]. "); try {setfile (filename, true, bufferedio, buffersize);} catch (ioexception e) {errorhandler. error ("setfile (" + filename + ", true) Call failed. ");}}}}

However, the preceding implementation has two problems:

1) concurrency

When closefile () is called in run (), the subappend () method writes logs. If the file is closed, the following error is reported:

java.io.IOException: Stream closedat 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)..............................

The solution is relatively simple. You can directly set the entire run () method to synchronous with the synchronized keyword. However, currentlyThe author did not solve the problem that logs may be lost if the writing speed is fast enough;

2) Performance

The implementation of timer is relatively simple, but if the execution time of tasks in timer is too long, the timer object will be exclusive, so that the subsequent tasks cannot be executed for a long time, and the solution is relatively simple, the thread pool version of the Timer class scheduledexecutorservice is used for implementation as follows:

/*****/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> * use scheduledexecutorservice to implement timed configuration and print logs * <p> **/public class scheduledexecutorserviceappender extends fileappender {/*** the date pattern. by default, the pattern is set "'. 'yyyy-mm-dd "* Meaning daily rolover. */Private Static final string datepattern = "'. 'yyyy-mm-dd-hh-mm '. log' ";/*** interval, in the unit of minute */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, 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;} @ overridepublic void activateoptions () {super. activateoptions (); executors. newsinglethreadscheduledexecutor (). scheduleatfixedrate (New logtimertask (), 1, intervaltime * 60000, timeunit. milliseconds);} class logtimertask implements runnable {@ overridepublic void run () {string datedfilename = filename + SDF. format (new date (); closefile (); file target = new file (datedfilename); If (target. exists () target. delete (); file = new file (filename); boolean result = file. renameto (target); If (result) loglog. debug (filename + "->" + datedfilename); elseloglog. error ("failed to rename [" + filename + "] to [" + datedfilename + "]. "); try {setfile (filename, true, bufferedio, buffersize);} catch (ioexception e) {errorhandler. error ("setfile (" + filename + ", true) Call failed. ");}}}}

The implementation of timing is almost here. By default, a new log file is generated in 10 minutes. You can set it during configuration, but there is a hidden danger,If the configured time interval is minuteWith a configuration of 600 and debug, it is a disaster to generate the log file of the G. The following transformation is to combine the maximum size of rollingfileappender and the maximum number of backup files to be matched, continue to describe the transformation process.

 

In addition, there are many good reference links for log4j, such:

1. http://www.iteye.com/topic/378077

2. http://www.cnblogs.com/duanxz/archive/2013/01/28/2880240.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.