- 浏览: 34242 次
- 性别:
- 来自: 合肥
博客专栏
-
我和Java数据库操作的那...
浏览量:9289
最新评论
-
ivanlw:
楼主用的这个snapito好神奇啊……是直接把图片链接设置成他 ...
ibookmark.me上线了! -
succinite:
使用TortoiseGit, 出现以下错误。fatal: ht ...
一个简单的JAVA后台程序框架 -
mazhiyuan:
引用很显然,之前所说的梦想,并非是真正心中所想,而只不过想“找 ...
也谈梦想 -
cevin15:
说到我心里去了。现在处于离职状态。也是对前途一片迷茫~
也谈梦想 -
lwjlaser:
lettoo 写道lwjlaser 写道这篇博客第一个示例代码 ...
我和JAVA数据库操作的那些事儿(3)
很多时候,log4j的RollingFileAppender配置如下:
RollingFileAppender会自动在一个文件满了之后,生成一个如text.log.1的文件,一直生成到text.log.x(x值可配置log4j.appender.file.MaxBackupIndex=10)为止,再回写text.log。
当我们有需要在产生一些自定义的log文件名的时候,比如:
test_[process_name]_0_20111031.log
test_[process_name]_1_20111031.log
test_[process_name]_2_20111031.log
......
要在文件名显示是哪一个进程名,第一个文件为0,后面是1,2,3......,并且要加上日期,再使用RollingFileAppender做简单的配置是无论如何也实现不了了。
打开RollingFileAppender.java的源码,我看到它主要是用setFile(),subAppend()和rollOver()这几个方法来实现具体的功能的:
如果我继承这个类,然后在子类里实现它的这三个方法,不就可以实现我要的功能了吗?
代码如下:
在setFile方法里,通过String的替换来实现我要的自定义字符串的功能,当然,这里只是一个示例。
文件满了之后生成新的文件编号,不再在log后面加数据,而是在文件名体现,我这里加了一个getRollingFileName()来根据正则表达式来替换。
当然,配置文件可以修改如下了:
虽然以上的做法满足了我的要求,但是我感觉也有缺点,主要是:
目前也没有想到更好的方法,暂时先记下来。
log4j.logger.cn.lettoo.Test=INFO, file log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.MaxFileSize=100KB log4j.appender.file.MaxBackupIndex=10 log4j.appender.file.File=test.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%d{MM/dd/yyyy HH:mm:ss.SSS} %m%n
RollingFileAppender会自动在一个文件满了之后,生成一个如text.log.1的文件,一直生成到text.log.x(x值可配置log4j.appender.file.MaxBackupIndex=10)为止,再回写text.log。
当我们有需要在产生一些自定义的log文件名的时候,比如:
引用
test_[process_name]_0_20111031.log
test_[process_name]_1_20111031.log
test_[process_name]_2_20111031.log
......
要在文件名显示是哪一个进程名,第一个文件为0,后面是1,2,3......,并且要加上日期,再使用RollingFileAppender做简单的配置是无论如何也实现不了了。
打开RollingFileAppender.java的源码,我看到它主要是用setFile(),subAppend()和rollOver()这几个方法来实现具体的功能的:
public // synchronization not necessary since doAppend is alreasy synched void rollOver() { File target; File file; if (qw != null) { long size = ((CountingQuietWriter) qw).getCount(); LogLog.debug("rolling over count=" + size); // if operation fails, do not roll again until // maxFileSize more bytes are written nextRollover = size + maxFileSize; } LogLog.debug("maxBackupIndex="+maxBackupIndex); boolean renameSucceeded = true; // If maxBackups <= 0, then there is no file renaming to be done. if(maxBackupIndex > 0) { // Delete the oldest file, to keep Windows happy. file = new File(fileName + '.' + maxBackupIndex); if (file.exists()) renameSucceeded = file.delete(); // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2} for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) { file = new File(fileName + "." + i); if (file.exists()) { target = new File(fileName + '.' + (i + 1)); LogLog.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); } } if(renameSucceeded) { // Rename fileName to fileName.1 target = new File(fileName + "." + 1); this.closeFile(); // keep windows happy. file = new File(fileName); LogLog.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); // // if file rename failed, reopen file with append = true // if (!renameSucceeded) { try { this.setFile(fileName, true, bufferedIO, bufferSize); } catch(IOException e) { if (e instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } LogLog.error("setFile("+fileName+", true) call failed.", e); } } } } // // if all renames were successful, then // if (renameSucceeded) { try { // This will also close the file. This is OK since multiple // close operations are safe. this.setFile(fileName, false, bufferedIO, bufferSize); nextRollover = 0; } catch(IOException e) { if (e instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } LogLog.error("setFile("+fileName+", false) call failed.", e); } } } public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException { super.setFile(fileName, append, this.bufferedIO, this.bufferSize); if(append) { File f = new File(fileName); ((CountingQuietWriter) qw).setCount(f.length()); } } /** This method differentiates RollingFileAppender from its super class. @since 0.9.0 */ protected void subAppend(LoggingEvent event) { super.subAppend(event); if(fileName != null && qw != null) { long size = ((CountingQuietWriter) qw).getCount(); if (size >= maxFileSize && size >= nextRollover) { rollOver(); } } }
如果我继承这个类,然后在子类里实现它的这三个方法,不就可以实现我要的功能了吗?
代码如下:
public class MWLogFileAppender extends RollingFileAppender { private long nextRollover = 0; public void rollOver() { File target; File file; if (qw != null) { long size = ((CountingQuietWriter) qw).getCount(); LogLog.debug("rolling over count=" + size); // if operation fails, do not roll again until // maxFileSize more bytes are written nextRollover = size + maxFileSize; } LogLog.debug("maxBackupIndex=" + maxBackupIndex); boolean renameSucceeded = true; // If maxBackups <= 0, then there is no file renaming to be done. if (maxBackupIndex > 0) { // Delete the oldest file, to keep Windows happy. //file = new File(fileName + '.' + maxBackupIndex); file = new File(getRollingFileName(fileName, maxBackupIndex)); if (file.exists()) renameSucceeded = file.delete(); // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, // 2} for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) { //file = new File(fileName + "." + i); file = new File(getRollingFileName(fileName, i)); if (file.exists()) { //target = new File(fileName + '.' + (i + 1)); target = new File(getRollingFileName(fileName, i+1)); LogLog.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); } } if (renameSucceeded) { // Rename fileName to fileName.1 //target = new File(fileName + "." + 1); target = new File(this.getRollingFileName(fileName, 1)); this.closeFile(); // keep windows happy. file = new File(fileName); LogLog.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); // // if file rename failed, reopen file with append = true // if (!renameSucceeded) { try { this.setFile(fileName, true, bufferedIO, bufferSize); } catch (IOException e) { if (e instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } LogLog.error("setFile(" + fileName + ", true) call failed.", e); } } } } // // if all renames were successful, then // if (renameSucceeded) { try { // This will also close the file. This is OK since multiple // close operations are safe. this.setFile(fileName, false, bufferedIO, bufferSize); nextRollover = 0; } catch (IOException e) { if (e instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } LogLog.error("setFile(" + fileName + ", false) call failed.", e); } } } private String getRollingFileName(String fileName, int index) { Pattern p = Pattern.compile("_\\d+\\."); Matcher m=p.matcher(fileName); return m.replaceFirst(String.format("_%d.", index)); } public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException { String processName = "01"; SimpleDateFormat format = new SimpleDateFormat("MMddyyyy"); String dateString = format.format(new Date(System.currentTimeMillis())); String processId = String.valueOf(Thread.currentThread().getId()); String temp = String.format(fileName, processName, dateString, processId); //System.out.println(temp); super.setFile(temp, append, bufferedIO, bufferSize); } protected void subAppend(LoggingEvent event) { super.subAppend(event); if (fileName != null && qw != null) { long size = ((CountingQuietWriter) qw).getCount(); if (size >= maxFileSize && size >= nextRollover) { rollOver(); } } } }
在setFile方法里,通过String的替换来实现我要的自定义字符串的功能,当然,这里只是一个示例。
文件满了之后生成新的文件编号,不再在log后面加数据,而是在文件名体现,我这里加了一个getRollingFileName()来根据正则表达式来替换。
当然,配置文件可以修改如下了:
log4j.logger.cn.lettoo.Test=INFO, file log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.MaxFileSize=100KB log4j.appender.file.MaxBackupIndex=10 log4j.appender.file.File=test-%s_%s_0.%s.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%d{MM/dd/yyyy HH:mm:ss.SSS} %m%n
虽然以上的做法满足了我的要求,但是我感觉也有缺点,主要是:
- 配置文件必须要按我自定义的格式来写,即log4j.appender.file.File=test-%s_%s_0.%s.log不能搞错了
- RollingFileAppender的几个方法扩展的都不好,还把原来的代码copy过来修改的。
目前也没有想到更好的方法,暂时先记下来。
发表评论
-
ibookmark.me上线了!
2012-04-10 23:47 1497记得上次是2009年,接触到了python,gae,于是乎动手 ... -
使用virtualenv开发django应用
2012-01-12 11:03 1739Virtualenv是一个非常好的virtual python ... -
在Amazon EC2上试用play framework
2011-11-11 17:00 1375几个月以前,我在 ... -
一个Log生成工具小项目的实现
2011-11-01 17:32 1331这两天的主要工作是用java写一个log生成工具,用于 ... -
我和java操作数据库那些事儿(5)
2011-10-26 16:56 1616引用 半自动化武器来了:Spring JdbcTemplate ... -
我和JAVA数据库操作的那些事儿(4)
2011-10-24 16:21 1475通过前面几篇的介绍,对于JDBC的使用应该基本上够上项目开发的 ... -
我和JAVA数据库操作的那些事儿(3)
2011-10-20 15:35 2461在前面的两篇文章中,第一篇主要是讲了在jdbc编程中容 ... -
我和JAVA数据库操作的那些事儿(2)
2011-10-20 11:15 1535摘要 写道 上一篇提到的几个问题,在本篇有具体的代码。本篇后 ... -
图说事务隔离级别
2011-10-19 21:38 1390我们经常说的事务隔离级别,一般指的是SQL-92 ... -
我和JAVA数据库操作的那些事儿(1)
2011-10-19 15:26 2205摘要 我开始接触jdbc的 ... -
复习:观察者模式
2011-10-17 17:02 959观察者模式(有时又被称为发布/订阅模式)是软件设计模式 ... -
复习:代理模式
2011-10-17 15:53 701代理模式是常用的Java 设计模式,它的特征是代理类与 ... -
对chainsaw中一个简单Job Scheduler的扩展
2011-10-14 23:36 1019今天在看apache chainsaw这个项目的源代码 ... -
Spring RMI 简单实现
2011-10-14 13:47 1024好久没有写java代码了,最近工作项目上需要做一个 ... -
一道关于树的面试题
2011-10-13 15:31 912记得不久以前有道面试题,要求下面的数据结构 ... -
一个简单的JAVA后台程序框架
2011-10-13 09:31 1723本项目已经通过git进行版本管理,checkout ... -
测试驱动开发:红、绿、重构
2011-10-12 23:01 864在读Ruby on Rails Tutorial: ... -
Spring JMS和ActiveMQ的应用
2011-10-12 22:43 2016笔者近期参与一个分析log的项目。主要流程是:读取Lo ...
相关推荐
过了时间将原日志文件命名为原文件名后加上log4j.appender.File.DatePattern='.'yyyy-MM-dd-HH对应格式的日期, 注意不能用:和_。 关于DailyRollingFileAppender的使用,参考:...
shiro,泛微OA,致远OA,通达OA等易受攻击组件的漏洞检测,支持调用dnslog平台检测无回显的rce(包括log4j2的检测),支持单个目标检测和批量检测,程序采用高并发线程池,支持自定义导入poc/exp,并能够生成漏洞报告 ...
附件文件名的截取 2、Runtime error, "Could not load file or assembly 'log4net," 修复运行时错误,“无法加载文件或程序集”log4net的 3、Open Issue count doesn't match 未解决问题数量不匹配 4、Deleted ...
12.SR.ShareFunc.WinFunc.LogFunc 按照指定路径、文件名生成日志信息 13.SR.ShareFunc.WinFunc.MouseMoveControl 给指定控件绑定鼠标移动事件,例如Label绑定后,鼠标点击该Label可进行窗体拖拽 或实现自定义的...
混淆结束后,处理前与处理后对应关系会记录在obf.map中,文件名可以自定义 参照附件中《obf.map》 注:该文档自动生成 8、《testjava.pro》是我自己的配置文档(一个helloWorld),仅供参考 9、日记《success-log....
fileContent字段映射为Spring所提供的BlobByteArrayType类型,BlobByteArrayType是用户自定义的数据类型,它实现了Hibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取...
A: 同一用户生成的Excel文件用同一个文件名,文件名可用用户ID号或SessionID号等可确信不重复字符串组成。这样新文件生成时自动覆盖上一文件。 B: 在Global.asa文件中设置Session_onEnd事件激发时,删除这个用户的...
4、颜色:支持CIE色彩空间,嵌入ICC Profile,直接生成印刷品质的PDF。 5、加密:支持128 Bits RC4 加密 6、路径:多种方式指定目标PDF文件名,支持PDF合并,支持添加附件。 7、Ultra PDF工具:批量转换,图片...
关于能自定义格式的、支持多语言的、支持多数据库的代码生成器的想法 发布Oracle存储过程包c#代码生成工具(CodeRobot) New Folder XCodeFactory3.0完全攻略--序 XCodeFactory3.0完全攻略--基本思想 XCodeFactory...
X-Scan-v3.2 使用说明 一. 系统要求:Windows NT/2000/XP/2003 理论上可运行于Windows NT系列操作... “扫描报告”项 - 扫描结束后生成的报告文件名,保存在LOG目录下。扫描报告目前支持TXT、HTML和XML三种格式。
修复Session模块中影响图像生成的代码错误;调整Vcode模块Base方法,使其返回验证码文本;修复了Wrong模块对AJAX请求识别错误的问题;新增用以缓存数据的Data模块;修复Setting模块中Set方法出错的问题;修复Page...
4.启动控制台时如不存在备份还原主文件将自动生成,默认存放镜像路径为硬盘最后分区 5.支持设置“自动备份”及“自动还原功能”的独立密码,安装者或装机商可以直接在这里 设置密码限制用户使用此功能,可有效防止用户...
“扫描报告”项 - 扫描结束后生成的报告文件名,保存在LOG目录下。扫描报告目前支持TXT、HTML和XML三种格式。 “其他设置”项: “跳过没有响应的主机” - 若目标主机不响应ICMP ECHO及TCP SYN报文,X-Scan将跳过...
当生成的压缩文件是自解压的并且压缩文件大小超过 4 GB,WinRAR 显示一个警告。 Windows 不能运行应用程序。 of such size. <br> 5. 修正 ISO 处理的代码。 <br> 版本 3.70 beta 2 <br> 1. 压缩...
Less等) 添加图像,字体和文件使用public文件夹更改HTML 在模块系统之外添加资产何时使用public文件夹使用全局变量添加引导程序使用自定义主题增加流量添加自定义环境变量在HTML中引用环境变量在Shell中添加临时...