`
huiqinbo
  • 浏览: 344400 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

为java.util.logging自定义文件处理器及日志输出格式

 
阅读更多

为java.util.logging自定义文件处理器及日志输出格式

       最近闲来无事,刚好拾起了来公司的第一个项目,发现里面的logging功能有点弱,竟然不支持按日期文件名输出,更惨的是由于引入了些apache的公用了包,一个项目里竟然同时出现logging,log4j,commons-logging,这年头引用下开源包还要用不同的loger.记得log4j好像支持输出的文件按日期来分类的,jdk自带的logging好像还没有,于是google了一把,发现JAVA中自定义日志输出格式及自定义文件处理器的实现 ,功能还不错,有些bug及不合理的地方,于是再修改下,凑合用用.

      直接代码:

 

  FileStreamHandler实现

Java代码 复制代码 收藏代码
  1. package com.huiqinbo;   
  2.   
  3. import java.io.BufferedOutputStream;   
  4. import java.io.File;   
  5. import java.io.FileOutputStream;   
  6. import java.io.IOException;   
  7. import java.io.OutputStream;   
  8. import java.text.SimpleDateFormat;   
  9. import java.util.Date;   
  10. import java.util.HashMap;   
  11. import java.util.Map;   
  12. import java.util.TreeSet;   
  13. import java.util.logging.Filter;   
  14. import java.util.logging.Formatter;   
  15. import java.util.logging.Handler;   
  16. import java.util.logging.Level;   
  17. import java.util.logging.LogManager;   
  18. import java.util.logging.LogRecord;   
  19. import java.util.logging.Logger;   
  20. import java.util.logging.StreamHandler;   
  21.   
  22. /**  
  23.  * 自定义日志文件处理器---日期及文件大小存储,并自动清除过期日志文件  
  24.  *   
  25.  * @author huiqinbo  
  26.  * @time 2008-9-11下午11:16:39  
  27.  */  
  28. public class XLFileStreamHandler extends StreamHandler {   
  29.     /**  
  30.      * 抄自FileHandler的实现,用于跟踪写入文件的字节数 这样以便提高效率  
  31.      */  
  32.     private class MeteredStream extends OutputStream {   
  33.   
  34.         private OutputStream out;   
  35.         // 记录当前写入字节数   
  36.         private int written;   
  37.   
  38.         MeteredStream(OutputStream out, int written) {   
  39.             this.out = out;   
  40.             this.written = written;   
  41.         }   
  42.   
  43.         public void close() throws IOException {   
  44.             out.close();   
  45.         }   
  46.   
  47.         public void flush() throws IOException {   
  48.             out.flush();   
  49.         }   
  50.   
  51.         public void write(byte buff[]) throws IOException {   
  52.             out.write(buff);   
  53.             written += buff.length;   
  54.         }   
  55.   
  56.         public void write(byte buff[], int off, int len) throws IOException {   
  57.             out.write(buff, off, len);   
  58.             written += len;   
  59.         }   
  60.   
  61.         public void write(int b) throws IOException {   
  62.             out.write(b);   
  63.             written++;   
  64.         }   
  65.     }   
  66.   
  67.     private class XLLogFile extends File {   
  68.         private static final long serialVersionUID = 952141123094287978L;   
  69.         private Date date;   
  70.         private String dateString;   
  71.         private int sid;   
  72.   
  73.         public int getSid() {   
  74.             return this.sid;   
  75.         }   
  76.   
  77.         public void setSid(int sid) {   
  78.             this.sid = sid;   
  79.         }   
  80.   
  81.         public Date getDate() {   
  82.             return this.date;   
  83.         }   
  84.   
  85.         public void setDate(Date date) {   
  86.             this.date = date;   
  87.         }   
  88.   
  89.         public String getDateString() {   
  90.             return this.dateString;   
  91.         }   
  92.   
  93.         public void setDateString(String dateString) {   
  94.             this.dateString = dateString;   
  95.         }   
  96.   
  97.         public int compareTo(File another) {   
  98.             XLLogFile ano = (XLLogFile) another;   
  99.             int dateComResult = date.compareTo(ano.getDate());   
  100.             if (dateComResult == 0) {   
  101.                 return sid - ano.getSid();   
  102.             }   
  103.             return dateComResult;   
  104.         }   
  105.   
  106.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");   
  107.   
  108.         public XLLogFile(String pathname) {   
  109.             super(pathname);   
  110.             try {   
  111.                 int dot = pathname.lastIndexOf('.');   
  112.                 int split = pathname.lastIndexOf(splitDateIndexChar);   
  113.                 int underline = pathname.lastIndexOf('_');   
  114.                 dateString = pathname.substring(underline + 1, split);   
  115.                 String numStr = pathname.substring(split + 1, dot);   
  116.                 date = sdf.parse(dateString);   
  117.                 sid = Integer.valueOf(numStr);   
  118.             } catch (Exception e) {   
  119.                 System.err.println("log对应文件夹中包含了不符合XLLOG格式的文件!!");   
  120.                 e.printStackTrace();   
  121.             }   
  122.   
  123.         }   
  124.     }   
  125.   
  126.     private static final String undifine = "xlcallcenter";   
  127.     // 是否将日志写入已存在的日志文件中   
  128.     private boolean append;   
  129.     // 保存几天之内的日志文件   
  130.     // 时间间隔小于等于0时表明不删除历史记录   
  131.     private int dateinterval = 5;   
  132.     // 保存存在的日志文件   
  133.     private Map<String, TreeSet<XLLogFile>> files;   
  134.     // 每个日志希望写入的最大字节数,如果日志达到最大字节数则当天日期的一个新的编号的日志文件将被创建,最新的日志记录在最大编号的文件中   
  135.     // 文件大小为小于等于0时表明不限制日志文件大小   
  136.     private int limit = 1048576 * 5;   
  137.     // 输出流   
  138.     private MeteredStream msOut;   
  139.     // 文件路径, 可以是个目录或希望的日志名称,如果是个目录则日志为"callcenter_zd"   
  140.     // 指定日志名称时不需要包括日期,程序会自动生成日志文件的生成日期及相应的编号   
  141.     private String pattern = "./log/xunleidemo";   
  142.     private char splitDateIndexChar = '#';   
  143.   
  144.     public XLFileStreamHandler() throws Exception {   
  145.         configure();   
  146.         openWriteFiles();   
  147.     }   
  148.   
  149.   
  150.     /**  
  151.      * 初始化自定义文件流处理器  
  152.      *   
  153.      * @param fileUrl  
  154.      *            文件路径, 可以是个目录或希望的日志名称,如果是个目录则日志为"callcenter_zd"  
  155.      *            指定日志名称时不需要包括日期,程序会自动生成日志文件的生成日期及相应的编号  
  156.      * @param limit  
  157.      *            每个日志希望写入的最大字节数,如果日志达到最大字节数则当天日期的一个新的编  
  158.      *            号的日志文件将被创建,最新的日志记录在最大编号的文件中  
  159.      * @param dateinterval  
  160.      *            保存几天之内的日志文件  
  161.      * @param append  
  162.      *            是否将日志写入已存在的日志文件中  
  163.      * @throws java.lang.Exception  
  164.      */  
  165.     public XLFileStreamHandler(String fileUrl, int limit, int dateinterval,   
  166.             boolean append) throws Exception {   
  167.         super();   
  168.         this.pattern = fileUrl;   
  169.         this.limit = limit;   
  170.         this.dateinterval = dateinterval;   
  171.         this.append = append;          
  172.         openWriteFiles();   
  173.     }   
  174.   
  175.     /**  
  176.      * 检查当前日志时间,删除过期日志  
  177.      */  
  178.     private void deleteExpiredLog() {   
  179.   
  180.         try {   
  181.             // 今天作为基准   
  182.             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");   
  183.             String today = sdf.format(new Date().getTime());   
  184.             // 删除过期日志   
  185.             for (String keyDate : files.keySet()) {   
  186.                 if ((sdf.parse(today).getTime() - sdf.parse(keyDate).getTime())   
  187.                         / (86400 * 1000) > dateinterval) {   
  188.                     TreeSet<XLLogFile> traceDateFiles = files.get(keyDate);   
  189.                     for (File deletingFile : traceDateFiles) {   
  190.                         // if(deletingFile.exists()) {   
  191.                         deletingFile.delete();   
  192.                         // }   
  193.                     }   
  194.                     files.remove(today);   
  195.                 }   
  196.             }   
  197.         } catch (Exception ex) {   
  198.             Logger.getLogger(XLFileStreamHandler.class.getName()).log(   
  199.                     Level.SEVERE, null, ex);   
  200.         }   
  201.     }   
  202.   
  203.     // Private method to configure a FileHandler from LogManager   
  204.     // properties and/or default values as specified in the class   
  205.     // javadoc.   
  206.     private void configure() {   
  207.         LogManager manager = LogManager.getLogManager();   
  208.         String cname = getClass().getName();   
  209.   
  210.         // 获得pattern   
  211.         pattern = manager.getProperty(cname + ".pattern");   
  212.         if (pattern == null) {   
  213.             pattern = "./log/xunleidemo";   
  214.         }   
  215.   
  216.         // 获得limit   
  217.         String limitVal = manager.getProperty(cname + ".limit");   
  218.         if (limitVal == null) {   
  219.             limit = 1048576 * 5;   
  220.         } else {   
  221.             try {   
  222.                 limit = Integer.parseInt(limitVal.trim());   
  223.                 // if (limit < 0) {   
  224.                 // limit = 1048576 * 5;   
  225.                 // }   
  226.             } catch (Exception ex) {   
  227.                 limit = 1048576 * 5;   
  228.             }   
  229.         }   
  230.   
  231.         // 获得formatter   
  232.         String formatVal = manager.getProperty(cname + ".formatter");   
  233.         if (formatVal == null) {   
  234.             setFormatter(new XLLogFormatter());   
  235.         } else {   
  236.             try {   
  237.                 Class clz = ClassLoader.getSystemClassLoader().loadClass(   
  238.                         formatVal);   
  239.                 setFormatter((Formatter) clz.newInstance());   
  240.             } catch (Exception ex) {   
  241.                 // We got one of a variety of exceptions in creating the   
  242.                 // class or creating an instance.   
  243.                 // Drop through.   
  244.             }   
  245.         }   
  246.   
  247.         // 获得append   
  248.         String appendVal = manager.getProperty(cname + ".append");   
  249.         if (appendVal == null) {   
  250.             append = false;   
  251.         } else {   
  252.             if (appendVal.equalsIgnoreCase("true") || appendVal.equals("1")) {   
  253.                 append = true;   
  254.             } else if (appendVal.equalsIgnoreCase("false")   
  255.                     || appendVal.equals("0")) {   
  256.                 append = false;   
  257.             }   
  258.         }   
  259.   
  260.         // 获得level   
  261.         String levelVal = manager.getProperty(cname + ".level");   
  262.         if (levelVal == null) {   
  263.             setLevel(Level.ALL);   
  264.         } else {   
  265.             try {   
  266.                 setLevel(Level.parse(levelVal.trim()));   
  267.             } catch (Exception ex) {   
  268.                 setLevel(Level.ALL);   
  269.             }   
  270.         }   
  271.   
  272.         // 获得dateinterval   
  273.         String dateintervalVal = manager.getProperty(cname + ".dateinterval");   
  274.         if (dateintervalVal == null) {   
  275.             dateinterval = 5;   
  276.         } else {   
  277.             try {   
  278.                 dateinterval = Integer.parseInt(dateintervalVal.trim());   
  279.                 if (dateinterval <= 0) {   
  280.                     dateinterval = 5;   
  281.                 }   
  282.             } catch (Exception ex) {   
  283.                 dateinterval = 5;   
  284.             }   
  285.         }   
  286.   
  287.         // 获得filter   
  288.         String filterVal = manager.getProperty(cname + ".filter");   
  289.         if (filterVal == null) {   
  290.             setFilter(null);   
  291.         } else {   
  292.             try {   
  293.                 Class clz = ClassLoader.getSystemClassLoader().loadClass(   
  294.                         filterVal);   
  295.                 setFilter((Filter) clz.newInstance());   
  296.             } catch (Exception ex) {   
  297.                 // We got one of a variety of exceptions in creating the   
  298.                 // class or creating an instance.   
  299.                 // Drop through.   
  300.             }   
  301.         }   
  302.   
  303.         // 获得encoding   
  304.         String encodingVal = manager.getProperty(cname + ".encoding");   
  305.         if (encodingVal == null) {   
  306.             try {   
  307.                 setEncoding(null);   
  308.             } catch (Exception ex2) {   
  309.                 // doing a setEncoding with null should always work.   
  310.                 // assert false;   
  311.             }   
  312.         } else {   
  313.             try {   
  314.                 setEncoding(encodingVal);   
  315.             } catch (Exception ex) {   
  316.                 try {   
  317.                     setEncoding(null);   
  318.                 } catch (Exception ex2) {   
  319.                     // doing a setEncoding with null should always work.   
  320.                     // assert false;   
  321.                 }   
  322.             }   
  323.         }   
  324.     }   
  325.   
  326.     /**  
  327.      * 将离现在最近的文件作为写入文件的文件 例如 xunleidemo_2008-02-19#30.log  
  328.      * xunleidemo表示自定义的日志文件名,2008-02-19表示日志文件的生成日期,30 表示此日期的第30个日志文件  
  329.      */  
  330.     private void openLastFile(boolean append) {   
  331.         try {   
  332.             super.close();   
  333.             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");   
  334.             String today = sdf.format(new Date().getTime());   
  335.   
  336.             // 如果没有包含当天的日期,则添加当天日期的日志文件   
  337.             boolean isFirstLogToday = false;   
  338.             if (!files.containsKey(today)) {   
  339.                 String logIndex = today + splitDateIndexChar + 1;   
  340.                 TreeSet<XLLogFile> todayFiles = new TreeSet<XLLogFile>();   
  341.                 todayFiles.add(getNewFile(logIndex));   
  342.                 files.put(today, todayFiles);   
  343.                 isFirstLogToday = true;   
  344.             }   
  345.   
  346.             // 获得今天最大的日志文件编号   
  347.             XLLogFile todayLastFile = files.get(today).last();   
  348.             int maxLogCount = todayLastFile.getSid();   
  349.             String logIndex = today + splitDateIndexChar   
  350.                     + (maxLogCount + (isFirstLogToday ? 0 : (append ? 0 : 1)));   
  351.             XLLogFile wantWriteFile = getNewFile(logIndex);   
  352.             files.get(today).add(wantWriteFile);   
  353.             openFile(wantWriteFile, append);   
  354.         } catch (Exception ex) {   
  355.             Logger.getLogger(XLFileStreamHandler.class.getName()).log(   
  356.                     Level.SEVERE, null, ex);   
  357.         }   
  358.     }   
  359.   
  360.     /**  
  361.      * 根据logIndex要建立File  
  362.      *   
  363.      * @param logIndex  
  364.      *            包含今天日期及编号,如2008-09-11#1  
  365.      * @return File  
  366.      */  
  367.     private XLLogFile getNewFile(String logIndex) {   
  368.         File file = new File(pattern);   
  369.         XLLogFile wantWriteFile = null;   
  370.         StringBuilder filePath = new StringBuilder(pattern);   
  371.         if (file.isDirectory()) {   
  372.             filePath.append(File.separator);   
  373.             filePath.append(undifine);   
  374.   
  375.         }   
  376.         filePath.append('_');   
  377.         filePath.append(logIndex);   
  378.         filePath.append(".log");   
  379.         wantWriteFile = new XLLogFile(filePath.toString());   
  380.         return wantWriteFile;   
  381.     }   
  382.   
  383.     /**  
  384.      * 读取已经记录的日志的时间信息  
  385.      */  
  386.     private Map<String, TreeSet<XLLogFile>> getRecodedLog() {   
  387.         Map<String, TreeSet<XLLogFile>> filesMap = new HashMap<String, TreeSet<XLLogFile>>();   
  388.         try {   
  389.             // 建立相关目录   
  390.             File file = new File(pattern);   
  391.             File fileDir = null;   
  392.             if (pattern.endsWith("/") || pattern.endsWith("\\")) {   
  393.                 // 是个目录   
  394.                 fileDir = file;   
  395.                 if (!file.exists()) {   
  396.                     file.mkdirs();   
  397.                 }   
  398.             } else {   
  399.                 // 带了前缀   
  400.                 File parentFile = new File(file.getParent());   
  401.                 fileDir = parentFile;   
  402.                 // 父目录不存在则新建目录   
  403.                 if (!parentFile.exists()) {   
  404.                     parentFile.mkdirs();   
  405.                 }   
  406.             }   
  407.   
  408.             // 加入到filesMap中   
  409.             for (File contentFile : fileDir.listFiles()) {   
  410.                 if (contentFile.isFile()) {   
  411.                     XLLogFile newXLLogFile = new XLLogFile(contentFile   
  412.                             .getAbsolutePath());   
  413.                     TreeSet<XLLogFile> fileListToDate = filesMap   
  414.                             .get(newXLLogFile.getDateString());   
  415.                     if (fileListToDate == null) {   
  416.                         fileListToDate = new TreeSet<XLLogFile>();   
  417.                     }   
  418.                     fileListToDate.add(newXLLogFile);   
  419.                     filesMap.put(newXLLogFile.getDateString(), fileListToDate);   
  420.                 }   
  421.             }   
  422.   
  423.             files = filesMap;   
  424.             return filesMap;   
  425.         } catch (Exception ex) {   
  426.             Logger.getLogger(XLFileStreamHandler.class.getName()).log(   
  427.                     Level.SEVERE, null, ex);   
  428.         }   
  429.         return null;   
  430.     }   
  431.   
  432.     /**  
  433.      * 打开需要写入的文件  
  434.      *   
  435.      * @param file  
  436.      *            需要打开的文件  
  437.      * @param append  
  438.      *            是否将内容添加到文件末尾  
  439.      */  
  440.     private void openFile(File file, boolean append) throws Exception {   
  441.         int len = 0;   
  442.         if (append) {   
  443.             len = (int) file.length();   
  444.         }   
  445.         FileOutputStream fout = new FileOutputStream(file.toString(), append);   
  446.         BufferedOutputStream bout = new BufferedOutputStream(fout);   
  447.         msOut = new MeteredStream(bout, len);   
  448.         setOutputStream(msOut);   
  449.     }   
  450.   
  451.     /**  
  452.      * 获得将要写入的文件  
  453.      */  
  454.     private synchronized void openWriteFiles() throws Exception {   
  455.         if (!getLevel().equals(Level.OFF)) {               
  456.             getRecodedLog();   
  457.             deleteExpiredLog();   
  458.             openLastFile(append);   
  459.         }   
  460.     }   
  461.   
  462.     /**  
  463.      * 发布日志信息  
  464.      */  
  465.     public synchronized void publish(LogRecord record) {   
  466.         super.publish(record);   
  467.         super.flush();   
  468.         if (getLevel().equals(Level.OFF)) {   
  469.             return;   
  470.         }   
  471.         if (limit > 0 && msOut.written >= limit) {   
  472.             openLastFile(false);   
  473.         }   
  474.     }   
  475.   
  476.     public static void main(String[] args) {   
  477.         Logger fileLogger = Logger.getLogger(XLFileStreamHandler.class  
  478.                 .getName());   
  479.         fileLogger.setLevel(Level.INFO);   
  480.         Handler[] hs = fileLogger.getHandlers();   
  481.         for (Handler h : hs) {   
  482.             h.close();   
  483.             fileLogger.removeHandler(h);   
  484.         }   
  485.         try {   
  486.             // 文件 日志文件名为mylog 日志最大写入为4000个字节 保存5天内的日志文件   
  487.             // 如果文件没有达到规定大小则将日志文件添加到已有文件   
  488.             XLFileStreamHandler fh = new XLFileStreamHandler("d:\\mylog\\test",   
  489.                     20010false);   
  490.             fh.setLevel(Level.OFF);   
  491.             fh.setEncoding("UTF-8");   
  492.             fh.setFormatter(new XLLogFormatter());   
  493.             fileLogger.setUseParentHandlers(false);   
  494.             fileLogger.addHandler(fh);   
  495.         } catch (Exception ex) {   
  496.             ex.printStackTrace();   
  497.         }   
  498.         for (int i = 0; i < 30; i++) {   
  499.             fileLogger.log(Level.INFO, "我被记录了吗?");   
  500.         }   
  501.     }   
  502. }  
package com.xunlei.demo.util;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import java.util.logging.Filter;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.StreamHandler;

/**
 * 自定义日志文件处理器---日期及文件大小存储,并自动清除过期日志文件
 * 
 * @author ZengDong
 * @since 2008-9-11下午11:16:39
 */
public class XLFileStreamHandler extends StreamHandler {
	/**
	 * 抄自FileHandler的实现,用于跟踪写入文件的字节数 这样以便提高效率
	 */
	private class MeteredStream extends OutputStream {

		private OutputStream out;
		// 记录当前写入字节数
		private int written;

		MeteredStream(OutputStream out, int written) {
			this.out = out;
			this.written = written;
		}

		public void close() throws IOException {
			out.close();
		}

		public void flush() throws IOException {
			out.flush();
		}

		public void write(byte buff[]) throws IOException {
			out.write(buff);
			written += buff.length;
		}

		public void write(byte buff[], int off, int len) throws IOException {
			out.write(buff, off, len);
			written += len;
		}

		public void write(int b) throws IOException {
			out.write(b);
			written++;
		}
	}

	private class XLLogFile extends File {
		private static final long serialVersionUID = 952141123094287978L;
		private Date date;
		private String dateString;
		private int sid;

		public int getSid() {
			return this.sid;
		}

		public void setSid(int sid) {
			this.sid = sid;
		}

		public Date getDate() {
			return this.date;
		}

		public void setDate(Date date) {
			this.date = date;
		}

		public String getDateString() {
			return this.dateString;
		}

		public void setDateString(String dateString) {
			this.dateString = dateString;
		}

		public int compareTo(File another) {
			XLLogFile ano = (XLLogFile) another;
			int dateComResult = date.compareTo(ano.getDate());
			if (dateComResult == 0) {
				return sid - ano.getSid();
			}
			return dateComResult;
		}

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

		public XLLogFile(String pathname) {
			super(pathname);
			try {
				int dot = pathname.lastIndexOf('.');
				int split = pathname.lastIndexOf(splitDateIndexChar);
				int underline = pathname.lastIndexOf('_');
				dateString = pathname.substring(underline + 1, split);
				String numStr = pathname.substring(split + 1, dot);
				date = sdf.parse(dateString);
				sid = Integer.valueOf(numStr);
			} catch (Exception e) {
				System.err.println("log对应文件夹中包含了不符合XLLOG格式的文件!!");
				e.printStackTrace();
			}

		}
	}

	private static final String undifine = "xlcallcenter";
	// 是否将日志写入已存在的日志文件中
	private boolean append;
	// 保存几天之内的日志文件
	// 时间间隔小于等于0时表明不删除历史记录
	private int dateinterval = 5;
	// 保存存在的日志文件
	private Map<String, TreeSet<XLLogFile>> files;
	// 每个日志希望写入的最大字节数,如果日志达到最大字节数则当天日期的一个新的编号的日志文件将被创建,最新的日志记录在最大编号的文件中
	// 文件大小为小于等于0时表明不限制日志文件大小
	private int limit = 1048576 * 5;
	// 输出流
	private MeteredStream msOut;
	// 文件路径, 可以是个目录或希望的日志名称,如果是个目录则日志为"callcenter_zd"
	// 指定日志名称时不需要包括日期,程序会自动生成日志文件的生成日期及相应的编号
	private String pattern = "./log/xunleidemo";
	private char splitDateIndexChar = '#';

	public XLFileStreamHandler() throws Exception {
		configure();
		openWriteFiles();
	}


	/**
	 * 初始化自定义文件流处理器
	 * 
	 * @param fileUrl
	 *            文件路径, 可以是个目录或希望的日志名称,如果是个目录则日志为"callcenter_zd"
	 *            指定日志名称时不需要包括日期,程序会自动生成日志文件的生成日期及相应的编号
	 * @param limit
	 *            每个日志希望写入的最大字节数,如果日志达到最大字节数则当天日期的一个新的编
	 *            号的日志文件将被创建,最新的日志记录在最大编号的文件中
	 * @param dateinterval
	 *            保存几天之内的日志文件
	 * @param append
	 *            是否将日志写入已存在的日志文件中
	 * @throws java.lang.Exception
	 */
	public XLFileStreamHandler(String fileUrl, int limit, int dateinterval,
			boolean append) throws Exception {
		super();
		this.pattern = fileUrl;
		this.limit = limit;
		this.dateinterval = dateinterval;
		this.append = append;		
		openWriteFiles();
	}

	/**
	 * 检查当前日志时间,删除过期日志
	 */
	private void deleteExpiredLog() {

		try {
			// 今天作为基准
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			String today = sdf.format(new Date().getTime());
			// 删除过期日志
			for (String keyDate : files.keySet()) {
				if ((sdf.parse(today).getTime() - sdf.parse(keyDate).getTime())
						/ (86400 * 1000) > dateinterval) {
					TreeSet<XLLogFile> traceDateFiles = files.get(keyDate);
					for (File deletingFile : traceDateFiles) {
						// if(deletingFile.exists()) {
						deletingFile.delete();
						// }
					}
					files.remove(today);
				}
			}
		} catch (Exception ex) {
			Logger.getLogger(XLFileStreamHandler.class.getName()).log(
					Level.SEVERE, null, ex);
		}
	}

	// Private method to configure a FileHandler from LogManager
	// properties and/or default values as specified in the class
	// javadoc.
	private void configure() {
		LogManager manager = LogManager.getLogManager();
		String cname = getClass().getName();

		// 获得pattern
		pattern = manager.getProperty(cname + ".pattern");
		if (pattern == null) {
			pattern = "./log/xunleidemo";
		}

		// 获得limit
		String limitVal = manager.getProperty(cname + ".limit");
		if (limitVal == null) {
			limit = 1048576 * 5;
		} else {
			try {
				limit = Integer.parseInt(limitVal.trim());
				// if (limit < 0) {
				// limit = 1048576 * 5;
				// }
			} catch (Exception ex) {
				limit = 1048576 * 5;
			}
		}

		// 获得formatter
		String formatVal = manager.getProperty(cname + ".formatter");
		if (formatVal == null) {
			setFormatter(new XLLogFormatter());
		} else {
			try {
				Class clz = ClassLoader.getSystemClassLoader().loadClass(
						formatVal);
				setFormatter((Formatter) clz.newInstance());
			} catch (Exception ex) {
				// We got one of a variety of exceptions in creating the
				// class or creating an instance.
				// Drop through.
			}
		}

		// 获得append
		String appendVal = manager.getProperty(cname + ".append");
		if (appendVal == null) {
			append = false;
		} else {
			if (appendVal.equalsIgnoreCase("true") || appendVal.equals("1")) {
				append = true;
			} else if (appendVal.equalsIgnoreCase("false")
					|| appendVal.equals("0")) {
				append = false;
			}
		}

		// 获得level
		String levelVal = manager.getProperty(cname + ".level");
		if (levelVal == null) {
			setLevel(Level.ALL);
		} else {
			try {
				setLevel(Level.parse(levelVal.trim()));
			} catch (Exception ex) {
				setLevel(Level.ALL);
			}
		}

		// 获得dateinterval
		String dateintervalVal = manager.getProperty(cname + ".dateinterval");
		if (dateintervalVal == null) {
			dateinterval = 5;
		} else {
			try {
				dateinterval = Integer.parseInt(dateintervalVal.trim());
				if (dateinterval <= 0) {
					dateinterval = 5;
				}
			} catch (Exception ex) {
				dateinterval = 5;
			}
		}

		// 获得filter
		String filterVal = manager.getProperty(cname + ".filter");
		if (filterVal == null) {
			setFilter(null);
		} else {
			try {
				Class clz = ClassLoader.getSystemClassLoader().loadClass(
						filterVal);
				setFilter((Filter) clz.newInstance());
			} catch (Exception ex) {
				// We got one of a variety of exceptions in creating the
				// class or creating an instance.
				// Drop through.
			}
		}

		// 获得encoding
		String encodingVal = manager.getProperty(cname + ".encoding");
		if (encodingVal == null) {
			try {
				setEncoding(null);
			} catch (Exception ex2) {
				// doing a setEncoding with null should always work.
				// assert false;
			}
		} else {
			try {
				setEncoding(encodingVal);
			} catch (Exception ex) {
				try {
					setEncoding(null);
				} catch (Exception ex2) {
					// doing a setEncoding with null should always work.
					// assert false;
				}
			}
		}
	}

	/**
	 * 将离现在最近的文件作为写入文件的文件 例如 xunleidemo_2008-02-19#30.log
	 * xunleidemo表示自定义的日志文件名,2008-02-19表示日志文件的生成日期,30 表示此日期的第30个日志文件
	 */
	private void openLastFile(boolean append) {
		try {
			super.close();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			String today = sdf.format(new Date().getTime());

			// 如果没有包含当天的日期,则添加当天日期的日志文件
			boolean isFirstLogToday = false;
			if (!files.containsKey(today)) {
				String logIndex = today + splitDateIndexChar + 1;
				TreeSet<XLLogFile> todayFiles = new TreeSet<XLLogFile>();
				todayFiles.add(getNewFile(logIndex));
				files.put(today, todayFiles);
				isFirstLogToday = true;
			}

			// 获得今天最大的日志文件编号
			XLLogFile todayLastFile = files.get(today).last();
			int maxLogCount = todayLastFile.getSid();
			String logIndex = today + splitDateIndexChar
					+ (maxLogCount + (isFirstLogToday ? 0 : (append ? 0 : 1)));
			XLLogFile wantWriteFile = getNewFile(logIndex);
			files.get(today).add(wantWriteFile);
			openFile(wantWriteFile, append);
		} catch (Exception ex) {
			Logger.getLogger(XLFileStreamHandler.class.getName()).log(
					Level.SEVERE, null, ex);
		}
	}

	/**
	 * 根据logIndex要建立File
	 * 
	 * @param logIndex
	 *            包含今天日期及编号,如2008-09-11#1
	 * @return File
	 */
	private XLLogFile getNewFile(String logIndex) {
		File file = new File(pattern);
		XLLogFile wantWriteFile = null;
		StringBuilder filePath = new StringBuilder(pattern);
		if (file.isDirectory()) {
			filePath.append(File.separator);
			filePath.append(undifine);

		}
		filePath.append('_');
		filePath.append(logIndex);
		filePath.append(".log");
		wantWriteFile = new XLLogFile(filePath.toString());
		return wantWriteFile;
	}

	/**
	 * 读取已经记录的日志的时间信息
	 */
	private Map<String, TreeSet<XLLogFile>> getRecodedLog() {
		Map<String, TreeSet<XLLogFile>> filesMap = new HashMap<String, TreeSet<XLLogFile>>();
		try {
			// 建立相关目录
			File file = new File(pattern);
			File fileDir = null;
			if (pattern.endsWith("/") || pattern.endsWith("\\")) {
				// 是个目录
				fileDir = file;
				if (!file.exists()) {
					file.mkdirs();
				}
			} else {
				// 带了前缀
				File parentFile = new File(file.getParent());
				fileDir = parentFile;
				// 父目录不存在则新建目录
				if (!parentFile.exists()) {
					parentFile.mkdirs();
				}
			}

			// 加入到filesMap中
			for (File contentFile : fileDir.listFiles()) {
				if (contentFile.isFile()) {
					XLLogFile newXLLogFile = new XLLogFile(contentFile
							.getAbsolutePath());
					TreeSet<XLLogFile> fileListToDate = filesMap
							.get(newXLLogFile.getDateString());
					if (fileListToDate == null) {
						fileListToDate = new TreeSet<XLLogFile>();
					}
					fileListToDate.add(newXLLogFile);
					filesMap.put(newXLLogFile.getDateString(), fileListToDate);
				}
			}

			files = filesMap;
			return filesMap;
		} catch (Exception ex) {
			Logger.getLogger(XLFileStreamHandler.class.getName()).log(
					Level.SEVERE, null, ex);
		}
		return null;
	}

	/**
	 * 打开需要写入的文件
	 * 
	 * @param file
	 *            需要打开的文件
	 * @param append
	 *            是否将内容添加到文件末尾
	 */
	private void openFile(File file, boolean append) throws Exception {
		int len = 0;
		if (append) {
			len = (int) file.length();
		}
		FileOutputStream fout = new FileOutputStream(file.toString(), append);
		BufferedOutputStream bout = new BufferedOutputStream(fout);
		msOut = new MeteredStream(bout, len);
		setOutputStream(msOut);
	}

	/**
	 * 获得将要写入的文件
	 */
	private synchronized void openWriteFiles() throws Exception {
		if (!getLevel().equals(Level.OFF)) {			
			getRecodedLog();
			deleteExpiredLog();
			openLastFile(append);
		}
	}

	/**
	 * 发布日志信息
	 */
	public synchronized void publish(LogRecord record) {
		super.publish(record);
		super.flush();
		if (getLevel().equals(Level.OFF)) {
			return;
		}
		if (limit > 0 && msOut.written >= limit) {
			openLastFile(false);
		}
	}

	public static void main(String[] args) {
		Logger fileLogger = Logger.getLogger(XLFileStreamHandler.class
				.getName());
		fileLogger.setLevel(Level.INFO);
		Handler[] hs = fileLogger.getHandlers();
		for (Handler h : hs) {
			h.close();
			fileLogger.removeHandler(h);
		}
		try {
			// 文件 日志文件名为mylog 日志最大写入为4000个字节 保存5天内的日志文件
			// 如果文件没有达到规定大小则将日志文件添加到已有文件
			XLFileStreamHandler fh = new XLFileStreamHandler("d:\\mylog\\test",
					200, 10, false);
			fh.setLevel(Level.OFF);
			fh.setEncoding("UTF-8");
			fh.setFormatter(new XLLogFormatter());
			fileLogger.setUseParentHandlers(false);
			fileLogger.addHandler(fh);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		for (int i = 0; i < 30; i++) {
			fileLogger.log(Level.INFO, "我被记录了吗?");
		}
	}
}

 

 

附带用到的

日志格式

Java代码 复制代码 收藏代码
  1. package com.xunlei.demo.util;   
  2.   
  3. import java.io.PrintWriter;   
  4. import java.io.StringWriter;   
  5. import java.text.DecimalFormat;   
  6. import java.util.Calendar;   
  7. import java.util.logging.LogRecord;   
  8.   
  9. /**  
  10.  * Print a brief summary of the LogRecord in a human readable. The summary will  
  11.  * typically be on a single line (unless it's too long :) ... what I meant to  
  12.  * say is that we don't add any line breaks).  
  13.  *   
  14.  * @author ZengDong  
  15.  */  
  16.   
  17. public class XLLogFormatter extends java.util.logging.Formatter {   
  18.     private static String lineSeparator = System.getProperty("line.separator");   
  19.   
  20.     static long startTime = System.currentTimeMillis();   
  21.     private static DecimalFormat threeDigFmt = new DecimalFormat("000");   
  22.     private static DecimalFormat twoDigFmt = new DecimalFormat("00");   
  23.   
  24.     /**  
  25.      * Format the given LogRecord.  
  26.      *   
  27.      * @param record  
  28.      *            the log record to be formatted.  
  29.      * @return a formatted log record  
  30.      */  
  31.     // private final static String format = "{0,date} {0,time}";   
  32.     // private MessageFormat formatter;   
  33.     // Date dat = new Date();   
  34.     // private Object args[] = new Object[1];   
  35.     public synchronized String format(LogRecord record) {   
  36.         StringBuilder sb = new StringBuilder();   
  37.         // dat.setTime(record.getMillis());   
  38.         // args[0] = dat;   
  39.         // StringBuffer text = new StringBuffer();   
  40.         // if (formatter == null) {   
  41.         // formatter = new MessageFormat(format);   
  42.         // }   
  43.         // formatter.format(args, text, null);   
  44.         // sb.append(text);   
  45.         // current time   
  46.         // Calendar cal = Calendar.getInstance();   
  47.         // int millis = cal.get(Calendar.MILLISECOND);   
  48.         // sb.append('.').append(threeDigFmt.format(millis)).append(' ');   
  49.   
  50.         // current time   
  51.         Calendar cal = Calendar.getInstance();   
  52.         int hour = cal.get(Calendar.HOUR_OF_DAY);   
  53.         int minutes = cal.get(Calendar.MINUTE);   
  54.         int seconds = cal.get(Calendar.SECOND);   
  55.         int millis = cal.get(Calendar.MILLISECOND);   
  56.         sb.append(twoDigFmt.format(hour)).append(':');   
  57.         sb.append(twoDigFmt.format(minutes)).append(':');   
  58.         sb.append(twoDigFmt.format(seconds)).append('.');   
  59.         sb.append(threeDigFmt.format(millis)).append(' ');   
  60.   
  61.         // log level   
  62.         sb.append(record.getLevel().getLocalizedName());   
  63.         sb.append(": ");   
  64.   
  65.         // caller method   
  66.         int lineNumber = inferCaller(record);   
  67.         String loggerName = record.getLoggerName();   
  68.   
  69.         if (loggerName == null)   
  70.             loggerName = record.getSourceClassName();   
  71.   
  72.         if (loggerName.startsWith("com.xunlei.callcenter.")) {   
  73.             sb.append(loggerName.substring("com.xunlei.callcenter.".length()));   
  74.         } else  
  75.             sb.append(record.getLoggerName());   
  76.   
  77.         if (record.getSourceMethodName() != null) {   
  78.             sb.append('.');   
  79.             sb.append(record.getSourceMethodName());   
  80.   
  81.             // include the line number if we have it.   
  82.             if (lineNumber != -1)   
  83.                 sb.append("().").append(Integer.toString(lineNumber));   
  84.             else  
  85.                 sb.append("()");   
  86.         }   
  87.         sb.append(' ');   
  88.         sb.append(record.getMessage());   
  89.         sb.append(lineSeparator);   
  90.         if (record.getThrown() != null) {   
  91.             try {   
  92.                 StringWriter sw = new StringWriter();   
  93.                 PrintWriter pw = new PrintWriter(sw);   
  94.                 record.getThrown().printStackTrace(pw);   
  95.                 pw.close();   
  96.                 sb.append(sw.toString());   
  97.             } catch (Exception ex) {   
  98.             }   
  99.         }   
  100.         return sb.toString();   
  101.     }   
  102.   
  103.     /**  
  104.      * Try to extract the name of the class and method that called the current  
  105.      * log statement.  
  106.      *   
  107.      * @param record  
  108.      *            the logrecord where class and method name should be stored.  
  109.      *   
  110.      * @return the line number that the call was made from in the caller.  
  111.      */  
  112.     private int inferCaller(LogRecord record) {   
  113.         // Get the stack trace.   
  114.         StackTraceElement stack[] = (new Throwable()).getStackTrace();   
  115.   
  116.         // the line number that the caller made the call from   
  117.         int lineNumber = -1;   
  118.   
  119.         // First, search back to a method in the XLCallCenter Logger class.   
  120.         int ix = 0;   
  121.         while (ix < stack.length) {   
  122.             StackTraceElement frame = stack[ix];   
  123.             String cname = frame.getClassName();   
  124.             if (cname.equals("com.xunlei.demo.util.Logger")) {   
  125.                 break;   
  126.             }   
  127.             ix++;   
  128.         }   
  129.         // Now search for the first frame before the XLCallCenter Logger class.   
  130.         while (ix < stack.length) {   
  131.             StackTraceElement frame = stack[ix];   
  132.             lineNumber = stack[ix].getLineNumber();   
  133.             String cname = frame.getClassName();   
  134.             if (!cname.equals("com.xunlei.demo.util.Logger")) {   
  135.                 // We've found the relevant frame.   
  136.                 record.setSourceClassName(cname);   
  137.                 record.setSourceMethodName(frame.getMethodName());   
  138.                 break;   
  139.             }   
  140.             ix++;   
  141.         }   
  142.   
  143.         return lineNumber;   
  144.     }   
  145. }
分享到:
评论

相关推荐

    java swing用Logger输出错误日志.docx

    在Swing应用中,我们同样可以使用Java内置的`java.util.logging`包来输出错误日志。这篇文档主要讨论了如何在Java Swing应用中使用`Logger`来生成和管理错误日志。 `Logger`是Java的日志记录工具,它提供了多种级别...

    Java Logger Logging 封装

    `Logger`是Java标准库`java.util.logging`包提供的日志工具,它提供了多种级别的日志记录,如`SEVERE`、`WARNING`、`INFO`、`CONFIG`、`FINE`、`FINER`和`FINEST`。本篇文章将深入探讨Java中的`Logger`封装,以及...

    tomcat7修改catalina.out日志按天生成jar文件

    例如,添加`java.util.logging.FileHandler.pattern`和`java.util.logging.FileHandler.limit`等属性,设置日志文件的命名规则(例如包含日期)以及每个文件的最大大小。 重起Tomcat后,新的配置才会生效。这意味着...

    Java原生日志工具Logger参考.docx

    `logging.properties`文件用于配置Java原生日志工具的行为,包括日志输出的目的地、格式以及过滤规则等。默认情况下,Java安装目录下的`jre/lib/logging.properties`文件会被用来初始化日志系统。 ##### 4.1 读取...

    通过DriverManager类提供的方法控制日志输出

    2. **使用Java Util Logging (JUL)**:这是Java内置的日志框架,可以设置系统属性(如`java.util.logging.LogManager.config`指向配置文件路径)或直接调用`Logger`类的方法来控制日志级别。例如,你可以使用`java....

    Java日志终极指南 - ImportNew1

    比如,`java.util.logging`的配置文件是`logging.properties`,其中定义了日志级别、处理器和输出格式等。开发者可以通过指定`java.util.logging.config.file`属性来使用自定义的配置文件。其他框架如Log4j和Logback...

    java中logging的demo

    6. **格式化日志**:可以创建`SimpleFormatter`或自定义`Formatter`来控制日志输出的格式。例如: ```java SimpleFormatter formatter = new SimpleFormatter(); fileHandler.setFormatter(formatter); ``` 7. ...

    JDK自带的日志包简单应用

    `MySimpleFormatter.java`可能定义了一个简单的日志格式化器,继承自`java.util.logging.Formatter`,并覆盖`format(LogRecord)`方法,以自定义日志输出的样式。默认的`SimpleFormatter`会输出一条简洁的消息,但...

    【Java基础笔记】JavaUtil日志.docx

    总结来说,JavaUtil日志提供了一套完整的日志管理方案,包括创建日志记录器、设置处理器以及定制日志格式,使得开发者能够根据需求灵活地调整日志的输出方式和内容。在实际开发中,合理使用这些功能可以帮助调试、...

    tomcat-7.0.26.tomcat-juli.jar

    Juli,全称为Java Util Logging,是Tomcat自定义的日志框架,它取代了早期版本中的Apache Commons Logging。Juli提供了更高效、更可控的日志处理机制,允许开发者针对不同的日志需求进行精细化配置。与Java内置的...

    对JDK log日志的扩展

    4. **格式化日志**:JDK提供了`java.util.logging.Formatter`类,用于控制日志消息的输出格式。我们可以创建自定义的Formatter,以满足特定的格式需求,比如添加时间戳、线程ID、类名等信息。 5. **使用第三方日志...

    syslog协议发送日志(java)

    在Java中实现syslog日志发送,我们可以使用开源库如`logback`或`java.util.logging`。以`logback`为例,我们需要配置`logback.xml`,添加一个syslog appender: ```xml &lt;appender name="SYSLOG" class="ch.qos....

    ibatis.util包

    1. **Logger**: Ibatis提供了一个日志接口`org.apache.ibatis.logging.Log`,而`ibatis.util.LogFactory`则负责根据用户配置的实现(如Log4j、SLF4J或Java内置的日志系统)创建对应的日志实例,用于记录SQL执行和...

    java中日志文件的配置及架包

    它的配置文件通常为logback.xml,同样支持多级别的日志输出和自定义布局。 3. **Java.util.logging**: Java内置的日志框架,简洁且易于集成。尽管功能相对较弱,但在小型项目或不希望引入额外依赖的场合,它是不错...

    tomcat日志配置所有包

    例如,`java.util.logging.ConsoleHandler`负责将日志输出到控制台,而`java.util.logging.FileHandler`则将日志写入文件。 5. **日志级别配置** - 通过调整日志级别的设置,可以控制哪些级别的信息被记录。例如,...

    JUL的简单日志实现

    - **自定义处理器**:可以继承`java.util.logging.Handler`类,实现自己的日志处理逻辑。 5. **过滤器(Filter)** - **控制日志输出**:通过实现`java.util.logging.Filter`接口,可以过滤特定的日志事件,只让...

    采用jdk实现的日志框架

    这个XML文件可能包含了日志记录级别设置、日志处理器(如控制台、文件或网络)的选择、过滤器的定义以及日志输出格式等。例如,你可以指定哪些类或包的日志应该被记录,以及这些日志应如何处理和存储。 在JDK的`...

    Tomcat日志catalina.out过大解决方案--使用logback按日轮转.rar

    在Java Web应用开发中,Tomcat作为常用的Servlet容器,其默认的日志系统是通过`catalina.out`文件记录所有标准输出和错误输出。当应用运行一段时间后,`catalina.out`文件可能会变得非常大,占用大量磁盘空间,这...

    java 日志系统软件源代码.zip

    3. 日志配置:Java日志系统可以通过配置文件(如logging.properties)来定制日志的行为,如日志输出的格式、级别、处理器等。 二、常见Java日志框架 1. Log4j:Apache的Log4j是Java中最广泛使用的日志框架,提供了...

    springboot-logging.zip

    Spring Boot默认集成了多个流行的日志框架,如Logback、Log4j2和Java Util Logging(JUL)。其中,Logback是Spring Boot的默认日志系统,因为它在性能和灵活性方面表现优秀。如果想切换到其他日志框架,可以通过排除...

Global site tag (gtag.js) - Google Analytics