- 浏览: 35405 次
- 性别:
- 来自: 合肥
博客专栏
-
我和Java数据库操作的那...
浏览量:9538
最新评论
-
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 1550记得上次是2009年,接触到了python,gae,于是乎动手 ... -
使用virtualenv开发django应用
2012-01-12 11:03 1789Virtualenv是一个非常好的virtual python ... -
在Amazon EC2上试用play framework
2011-11-11 17:00 1425几个月以前,我在 ... -
一个Log生成工具小项目的实现
2011-11-01 17:32 1386这两天的主要工作是用java写一个log生成工具,用于 ... -
我和java操作数据库那些事儿(5)
2011-10-26 16:56 1671引用 半自动化武器来了:Spring JdbcTemplate ... -
我和JAVA数据库操作的那些事儿(4)
2011-10-24 16:21 1502通过前面几篇的介绍,对于JDBC的使用应该基本上够上项目开发的 ... -
我和JAVA数据库操作的那些事儿(3)
2011-10-20 15:35 2547在前面的两篇文章中,第一篇主要是讲了在jdbc编程中容 ... -
我和JAVA数据库操作的那些事儿(2)
2011-10-20 11:15 1581摘要 写道 上一篇提到的几个问题,在本篇有具体的代码。本篇后 ... -
图说事务隔离级别
2011-10-19 21:38 1451我们经常说的事务隔离级别,一般指的是SQL-92 ... -
我和JAVA数据库操作的那些事儿(1)
2011-10-19 15:26 2237摘要 我开始接触jdbc的 ... -
复习:观察者模式
2011-10-17 17:02 1003观察者模式(有时又被称为发布/订阅模式)是软件设计模式 ... -
复习:代理模式
2011-10-17 15:53 748代理模式是常用的Java 设计模式,它的特征是代理类与 ... -
对chainsaw中一个简单Job Scheduler的扩展
2011-10-14 23:36 1080今天在看apache chainsaw这个项目的源代码 ... -
Spring RMI 简单实现
2011-10-14 13:47 1066好久没有写java代码了,最近工作项目上需要做一个 ... -
一道关于树的面试题
2011-10-13 15:31 949记得不久以前有道面试题,要求下面的数据结构 ... -
一个简单的JAVA后台程序框架
2011-10-13 09:31 1788本项目已经通过git进行版本管理,checkout ... -
测试驱动开发:红、绿、重构
2011-10-12 23:01 901在读Ruby on Rails Tutorial: ... -
Spring JMS和ActiveMQ的应用
2011-10-12 22:43 2082笔者近期参与一个分析log的项目。主要流程是:读取Lo ...
相关推荐
当我们面对特定项目需求,比如需要自定义日志文件名和日志输出格式时,Log4j同样提供了相应的解决方案。 首先,让我们深入理解如何自定义日志文件名。默认情况下,Log4j的日志文件名通常是固定的或者基于时间戳生成...
本文将深入探讨如何利用Log4j生成动态的日志文件名以及动态创建文件夹,帮助开发者更好地管理和分析应用程序的运行状态。 Log4j是一款功能强大的开源日志组件,它允许程序员灵活地控制日志信息的输出级别,如DEBUG...
Log4j是Apache的一个开源项目,它为Java应用程序提供了一个灵活的日志系统。这个系统能够帮助开发者记录程序运行过程中的各种信息,包括错误、警告、调试信息等,这对于软件的维护和故障排查至关重要。Log4j的核心...
Log4j的核心在于其灵活性,可以通过自定义布局模板来控制日志输出的格式。最常用的布局模板类是PatternLayout,它允许用户通过特定的模式字符串定义输出格式。例如,一个常见的模式是`%d{yyyy-MM-dd HH:mm:ss} %-5p ...
关于appender,如`log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender`,表示A2是一个每日滚动的日志文件appender,日志文件名是DAOLog,每天生成一个新的文件,并按照'.'yyyy-MM-dd的格式进行日期切分。...
通过以上介绍,我们了解到Log4j是一款非常强大的日志管理工具,它不仅提供了丰富的配置选项,还允许用户根据实际需求自定义日志级别、输出目的地及格式等。掌握Log4j的配置技巧对于提高软件开发效率和质量有着重要...
过了时间将原日志文件命名为原文件名后加上log4j.appender.File.DatePattern='.'yyyy-MM-dd-HH对应格式的日期, 注意不能用:和_。 关于DailyRollingFileAppender的使用,参考:...
`log4j.properties`是Apache Log4j库中用于配置日志记录行为的核心配置文件。下面将详细解析`log4j.properties`的配置项及其作用,同时提供实例来加深理解。 ### 1. Logger 日志记录的核心是`Logger`,它是Log4j中...
【标题】"mybatis查询入门(log4j控制台sql语句日记输出的)"涉及的知识点主要集中在MyBatis框架的基础使用以及如何通过Log4j在控制台输出SQL语句,以便于调试和优化数据库操作。MyBatis是一个轻量级的Java持久层框架...
此外,Log4j还支持自定义每条日志的输出格式,并且可以定义每条日志信息的级别,从而精细化地控制日志生成过程。特别的是,这些配置都可以通过一个外部配置文件完成,无需改动应用程序的源代码,极大地提高了灵活性...
**log4net 使用代码配置详解...在提供的`Log4NetTest2010`压缩包中,可能包含了一个简单的示例项目,展示了如何在实际应用中使用上述代码配置方法。通过研究这个项目,你可以更深入地理解`log4net`的代码配置工作原理。
4. **Mybatis SQL打印**:当Log4j配置正确后,Mybatis会在执行每个SQL语句时,自动打印出SQL的执行信息,包括动态生成的SQL语句及其参数。 5. **实例演示**:创建一个简单的Mybatis项目,配置Log4j,并编写一个...
Log4j 配置文件 Log4j 是一个功能强大且灵活的日志记录系统,它可以将日志信息输出到控制台、文件、数据库等多种目标。配置文件是 Log4j 的核心组件,用于定义日志记录的级别、输出目标、格式等信息。 配置根 ...
Log4j还支持自定义日志格式,通过`PatternLayout`可以定制输出格式,例如: ``` log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{ABSOLUTE}...
本文将详细解析log4j配置中的输出格式化符号,帮助读者更深入地理解和应用log4j。 ### log4j格式化符号详解 #### 1. `%p`: 日志级别 - `%p`表示日志级别,通常会输出DEBUG、INFO、WARN、ERROR、FATAL等不同级别的...
Log4j还允许用户自定义日志输出的格式。常用的格式化选项包括: - `%p`:日志级别(DEBUG、INFO、WARN、ERROR、FATAL)。 - `%d`:日志时间,默认格式为ISO8601,也可以自定义格式,例如`%d{yyyy-MM-dd HH:mm:ss....
标题提到的是一个针对`Log4j`的扩展,名为`DayRollingFileAppender`,它是一个按天滚动的日志Appender,同时也支持动态日志生成。这个Appender允许日志文件按照日期进行分割,避免单个日志文件过大导致的管理困难。 ...
除了上述基本模式外,Log4j还支持扩展模式,允许用户自定义字段的显示方式,如调整字段宽度和对齐方式: 1. **`%20c`**: 表示右对齐的类别名称,总宽度为20个字符,如果类别名称不足20个字符,则右侧填充空格。 2. ...
SLF4J支持自定义日志输出格式,例如使用PatternLayout在Log4j中配置 `%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n`,输出日期、优先级、类名、行号和消息。 **7. 异常处理** SLF4J允许直接传递异常对象给日志...
### jBoss下通过配置Log4j实现Web应用的日志管理 #### 一、Log4j简介与重要性 Log4j是一款广泛使用的Java日志框架,由Apache软件基金会开发维护。它提供了一种灵活的方式来控制应用程序日志的生成,允许开发者...