Log4j A Java code instance that periodically prints the log and adds a module name configuration _java

Source: Internet
Author: User
Tags date now log4j

Configure interval time, print log periodically
received a demand, through the log4j time print log, requirements described as follows: the need to be able to print the log regularly, the interval can be matched. When it comes to timing, first think of the Dailyrollingfileappender class, various timing, according to Datepattern, this can refer to class SimpleDateFormat class, common some of the regular settings are as follows:

    • '.' YYYY-MM: Monthly
    • '.' YYYY-WW: Weekly
    • '.' YYYY-MM-DD: Every day
    • '.' Yyyy-mm-dd-a: two times a day
    • '.' YYYY-MM-DD-HH: Per hour
    • '.' YYYY-MM-DD-HH-MM: Per minute

By observing that there are no n-minute similar date formats, a custom class is written based on the Dailyrollingfileappender class. The process is as follows:

1 copy dailyrollingfileappender type source code and renamed Minuterollingappender, in order to configure in Log4j.xml, add configuration Items intervaltime and adding set, get method;

private int intervaltime = 10; 

2) because the Dailyrollingfileappender class uses the Rollingcalendar class to compute the next interval, it needs to pass the parameter intervaltime, so modify the Rollingcalendar class as an inner class Because the method is to calculate the time of the next rollover action according to Datepattern, no other time pattern is needed at this time, and 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 According to the Minutes, the time pattern needs to be disabled, change it to static final, the response to remove its get, set method and Minuterollingappender constructor Datepattern parameters

private static String Datepattern = "'. ' yyyy-mm-dd-hh-mm '. log ' "; 

Similarly, the method of serving a variety of datepattern computecheckperiod () can also be deleted; So the transformation is done and the categories are 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; 
 /** * per minute configurable Appender * * @author coder_xia * */public class Minuterollingappender extends Fileappender { /** * the date pattern. By default, the # is set to '. ' 
  Yyyy-mm-dd "* meaning daily rollover. * * private static String Datepattern = "'. ' 
 yyyy-mm-dd-hh-mm '. log ' "; 
 
 /** * Interval time, Unit: minutes */private int intervaltime = 10; /** * The log file would be renamed to the value of the the scheduledfilename * variable then the next interval is Entere D. For example, if the rollover * period is one hour, the log file would be renamed to the value of * "sCheduledfilename "At the beginning of the next hour. 
  * The precise time is 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 a <code>MinuteRollingAppender</code> Open the file * designated by &LT;CODE&GT;FILENAME&LT;/CODE&GT;. 
  The opened filename would become the * ouput destination for this appender. * * Public Minuterollingappender (Layout Layout, String filename) throws IOException {super (Layout, filename, tr 
  UE); 
 Activateoptions (); 
 }/** * @return the intervaltime */public int getintervaltime () {return intervaltime; 
  } 
 
 /*** @param intervaltime * The intervaltime to set */public void setintervaltime (int intervaltime) {This.int 
 Ervaltime = 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 the '//within of the ' current bounds. 
  Rollover'll 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'll 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 the Minuterollingappender from its super class. * * <p> * Before actually logging, this method would check whether it are time to do * a rollover. If IT is, it would 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 (); The catch (IOException IoE) {if (IoE instanceof interruptedioexception) {Thread.CurrentThread (). In 
    Terrupt (); 
   } 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 =-35603317706018 
 
  14177L; 
  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"/> 
  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> 

On the timing of implementation, you can also use Java provided timer implementation, but also eliminates each log when the calculation and comparison of time, the difference is actually a thread and call the rollover method, implemented 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; The public class Timertaskrollingappender extends Fileappender {/** * is the date pattern. By default, the # is set to '. ' 
  Yyyy-mm-dd "* meaning daily rollover. * * private static final String Datepattern = "'. ' 
 
 yyyy-mm-dd-hh-mm '. log ' "; 
 
 /** * Interval time, Unit: minutes */private int intervaltime = 10; 
 
 SimpleDateFormat SDF = new SimpleDateFormat (Datepattern); 
  /** * The default constructor does nothing. * * Public Timertaskrollingappender () {}/** * Instantiate a <code>timertaskrollingappender</code&gt ; and open the file * designated by &LT;CODE&GT;FILENAME&LT;/CODE&GT;. The opened filename would 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. "); 
 } 
 } 
}

However, the above implementation, there are 2 problems:

1) Concurrent

A concurrency problem can occur in a place called CloseFile () in Run (), and then just subappend the () method to write the log, and the file is now closed, the following error is reported:

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) 
.............................. 

The solution is relatively simple, directly let the whole run () method for synchronization, plus synchronized keyword can be, but at present the landlord does not solve if you really want to write, and write fast enough circumstances may lose the log;
2) Performance

The use of timer implementation is relatively simple, but the timer inside the task if the execution time is too long, will monopolize the timer object, so that the next task can not be implemented, the solution is relatively simple, using the thread pool version of the Timer class Scheduledexecutorservice, Implemented 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> * using Scheduledexecutorservice to implement timed configuration print log * <p> * * * Public clas S Scheduledexecutorserviceappender extends Fileappender {/** * the date pattern. By default, the # is set to '. ' 
  Yyyy-mm-dd "* meaning daily rollover. * * private static final String Datepattern = "'. ' 
 
 yyyy-mm-dd-hh-mm '. log ' "; 
 
 /** * Interval time, Unit: minutes */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 &LT;CODE&GT;FILENAME&LT;/CODE&GT;. 
  The opened filename would become * The ouput destination for this appender. * * Public Scheduledexecutorserviceappender (Layout Layout, String filename) throws IOException {super (Layout, F 
  Ilename, 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, T 
 Imeunit.milliseconds); Class Logtimertask implements Runnable {@Override public void run () {String datedfilename = Filenam E + 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. "); 

 } 
 } 
}

About the timing of the implementation, almost here, using the default is 10 minutes to generate a new log file, in the configuration can be set up, but there is a hidden danger, in case the configuration of the person does not know the time interval is minutes, if it is seconds, with a 600, and opened the debug, the production of G on the log file, This must be a disaster, the following transformation is combined with the maximum size of the rollingfileappender and the maximum number of backup files can be matched, again to improve the next time to describe the transformation process.

Add Module name Configuration
in front of the log4j custom class implementation of regular printing, do not specify the size and specify the number of backup files, from the Rollingfileappender class copy code to the previous custom class to add, the only thing to solve is the concurrency problem, When a log event occurs when a file closes the rename file, an error is reported for the output stream closed.

There are now such scenarios, and often:

1. The project contains a number of different projects;

2. The same project contains different modules.

In the first case, you can configure log4j<catogery= "Test" and then use a similar method when generating logger:

Logger Logger=logger.getlogger ("Test"); 

In the second case, we want to be able to print different modules to the same log file, but want to be able to print out the log module name in order to locate problems, so there is a need for this article in the Appender class to add configuration ModuleName, the following began to transform, and the timing of the printing is different We use the Rollingfileappender class as the base class for the transformation.

First, add the configuration item modulename, and increase the get, set method;

Because inherit from Rollingfileappender, so only need in Subappend () format the data in Loggingevent, add FormatInfo method format data, code slightly;

The final finished product class is as follows:

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;  /** * Format Print content * * @param 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); 

 } 
}

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.