代码人,废话不多,直接上代码
主要重写部分,请关注以下代码和OdySession.getTraceTicket()相关联处!
还有一种解决方案,应用Log4j MDC技术,相关文档请搜索Log4j MDC。
MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能。
package com.zcm.log; import com.odianyun.architecture.caddy.trace.session.OdySession; import org.apache.log4j.Layout; import org.apache.log4j.spi.LoggingEvent; import org.apache.log4j.helpers.PatternParser; import org.apache.log4j.helpers.PatternConverter; public class ZcmPatternLayout extends Layout { public final static String DEFAULT_CONVERSION_PATTERN ="%m%n"; public final static String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n"; protected final int BUF_SIZE = 256; protected final int MAX_CAPACITY = 1024; private StringBuffer sbuf = new StringBuffer(BUF_SIZE); private String pattern; private PatternConverter head; public ZcmPatternLayout() { this(DEFAULT_CONVERSION_PATTERN); } public ZcmPatternLayout(String pattern) { this.pattern = pattern; head = createPatternParser((pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern).parse(); } public void setConversionPattern(String conversionPattern) { pattern = conversionPattern; head = createPatternParser(conversionPattern).parse(); } public String getConversionPattern() { return pattern; } public void activateOptions() { // nothing to do. } public boolean ignoresThrowable() { return true; } protected PatternParser createPatternParser(String pattern) { return new PatternParser(pattern); } public String format(LoggingEvent event) { // Reset working stringbuffer if(sbuf.capacity() > MAX_CAPACITY) { sbuf = new StringBuffer(BUF_SIZE); } else { sbuf.setLength(0); } PatternConverter c = head; while(c != null) { c.format(sbuf, event); c = c.next; } String ticket = OdySession.getTraceTicket(); return ticket == null?this.sbuf.toString():"[ticket:" + OdySession.getTraceTicket() + "] " + this.sbuf.toString(); } }
package com.zcm.log; import com.odianyun.architecture.caddy.trace.session.OdySession; import org.apache.log4j.FileAppender; import org.apache.log4j.Layout; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.text.SimpleDateFormat; import java.util.*; import java.io.IOException; import java.io.File; import java.io.InterruptedIOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar; import java.util.Calendar; import java.util.TimeZone; import java.util.Locale; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; public class ZcmRollingFileAppender extends FileAppender { // The code assumes that the following constants are in a increasing // sequence. static final int TOP_OF_TROUBLE=-1; static final int TOP_OF_MINUTE = 0; static final int TOP_OF_HOUR = 1; static final int HALF_DAY = 2; static final int TOP_OF_DAY = 3; static final int TOP_OF_WEEK = 4; static final int TOP_OF_MONTH = 5; /** The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. */ private String datePattern = "'.'yyyy-MM-dd"; /** The log file will be renamed to the value of the scheduledFilename variable when the next interval is entered. For example, if the rollover 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 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(); int checkPeriod = TOP_OF_TROUBLE; // The gmtTimeZone is used only in computeCheckPeriod() method. static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT"); /** The default constructor does nothing. */ public ZcmRollingFileAppender() { } /** Instantiate a <code>DailyRollingFileAppender</code> and open the file designated by <code>filename</code>. The opened filename will become the ouput destination for this appender. */ public ZcmRollingFileAppender (Layout layout, String filename, String datePattern) throws IOException { super(layout, filename, true); this.datePattern = datePattern; activateOptions(); } /** The <b>DatePattern</b> takes a string in the same format as expected by {@link SimpleDateFormat}. This options determines the rollover schedule. */ public void setDatePattern(String pattern) { datePattern = pattern; } /** Returns the value of the <b>DatePattern</b> option. */ public String getDatePattern() { return datePattern; } public void activateOptions() { super.activateOptions(); if(datePattern != null && fileName != null) { now.setTime(System.currentTimeMillis()); sdf = new SimpleDateFormat(datePattern); int type = computeCheckPeriod(); printPeriodicity(type); rc.setType(type); 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 + "]."); } } void printPeriodicity(int type) { switch(type) { case TOP_OF_MINUTE: LogLog.debug("Appender ["+name+"] to be rolled every minute."); break; case TOP_OF_HOUR: LogLog.debug("Appender ["+name +"] to be rolled on top of every hour."); break; case HALF_DAY: LogLog.debug("Appender ["+name +"] to be rolled at midday and midnight."); break; case TOP_OF_DAY: LogLog.debug("Appender ["+name +"] to be rolled at midnight."); break; case TOP_OF_WEEK: LogLog.debug("Appender ["+name +"] to be rolled at start of week."); break; case TOP_OF_MONTH: LogLog.debug("Appender ["+name +"] to be rolled at start of every month."); break; default: LogLog.warn("Unknown periodicity for appender ["+name+"]."); } } // This method computes the roll over period by looping over the // periods, starting with the shortest, and stopping when the r0 is // different from from r1, where r0 is the epoch formatted according // the datePattern (supplied by the user) and r1 is the // epoch+nextMillis(i) formatted according to datePattern. All date // formatting is done in GMT and not local format because the test // logic is based on comparisons relative to 1970-01-01 00:00:00 // GMT (the epoch). int computeCheckPeriod() { RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault()); // set sate to 1970-01-01 00:00:00 GMT Date epoch = new Date(0); if(datePattern != null) { for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern); simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT String r0 = simpleDateFormat.format(epoch); rollingCalendar.setType(i); Date next = new Date(rollingCalendar.getNextCheckMillis(epoch)); String r1 = simpleDateFormat.format(next); //System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1); if(r0 != null && r1 != null && !r0.equals(r1)) { return i; } } } return TOP_OF_TROUBLE; // Deliberately head for trouble... } /** Rollover the current file to a new file. */ void rollOver() throws IOException { /* Compute filename, but only if datePattern is specified */ if (datePattern == null) { errorHandler.error("Missing DatePattern option in rollOver()."); return; } String datedFilename = fileName+sdf.format(now); // It is too early to roll over because we are still within the // bounds of the current interval. Rollover will 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 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 DailyRollingFileAppender from its * super class. * * <p>Before actually logging, this method will check whether it is * time to do a rollover. If it is, it will schedule the next * rollover time and then rollover. * */ protected void subAppend(LoggingEvent event) { long n = System.currentTimeMillis(); if (n >= nextCheck) { now.setTime(n); nextCheck = rc.getNextCheckMillis(now); try { rollOver(); } catch(IOException ioe) { if (ioe instanceof InterruptedIOException) { Thread.currentThread().interrupt(); } LogLog.error("rollOver() failed.", ioe); } } this.qw.write(this.layout.format(event)); if(layout.ignoresThrowable()) { String[] s = event.getThrowableStrRep(); if (s != null) { int len = s.length; for(int i = 0; i < len; i++) { if (i == 0){ this.qw.write("[ticket:" + OdySession.getTraceTicket() + "] "); } this.qw.write(s[i]); this.qw.write(Layout.LINE_SEP); } } } if(shouldFlush(event)) { this.qw.flush(); } } } /** * RollingCalendar is a helper class to DailyRollingFileAppender. * 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 = -3560331770601814177L; int type = ZcmRollingFileAppender.TOP_OF_TROUBLE; RollingCalendar() { super(); } RollingCalendar(TimeZone tz, Locale locale) { super(tz, locale); } void setType(int type) { this.type = type; } public long getNextCheckMillis(Date now) { return getNextCheckDate(now).getTime(); } public Date getNextCheckDate(Date now) { this.setTime(now); switch(type) { case ZcmRollingFileAppender.TOP_OF_MINUTE: this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); this.add(Calendar.MINUTE, 1); break; case ZcmRollingFileAppender.TOP_OF_HOUR: this.set(Calendar.MINUTE, 0); this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); this.add(Calendar.HOUR_OF_DAY, 1); break; case ZcmRollingFileAppender.HALF_DAY: this.set(Calendar.MINUTE, 0); this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); int hour = get(Calendar.HOUR_OF_DAY); if(hour < 12) { this.set(Calendar.HOUR_OF_DAY, 12); } else { this.set(Calendar.HOUR_OF_DAY, 0); this.add(Calendar.DAY_OF_MONTH, 1); } break; case ZcmRollingFileAppender.TOP_OF_DAY: this.set(Calendar.HOUR_OF_DAY, 0); this.set(Calendar.MINUTE, 0); this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); this.add(Calendar.DATE, 1); break; case ZcmRollingFileAppender.TOP_OF_WEEK: this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek()); this.set(Calendar.HOUR_OF_DAY, 0); this.set(Calendar.MINUTE, 0); this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); this.add(Calendar.WEEK_OF_YEAR, 1); break; case ZcmRollingFileAppender.TOP_OF_MONTH: this.set(Calendar.DATE, 1); this.set(Calendar.HOUR_OF_DAY, 0); this.set(Calendar.MINUTE, 0); this.set(Calendar.SECOND, 0); this.set(Calendar.MILLISECOND, 0); this.add(Calendar.MONTH, 1); break; default: throw new IllegalStateException("Unknown periodicity type."); } return getTime(); } }
相关推荐
根据项目需要,要求日志文件名及输出的日志内容头为特殊的格式,因此重写了log4j的一些方法,如要求的格式和项目不同,可根据示例参考进行再次的修改
参照了几个网上大神配置,部分教程的描述有误,最终调试完成,可以实现kettle日志输出,测试版本...需要替换的文件为,Kettle的程序目录下data-integration-6.0\plugins\kettle5-log4j-plugin中有一个log4j.xml文件。
log4j、日志输出、自定义日志、多文件输出。
本工程主要实现log4j输出多个自定义路径的日志文件,为方便大家使用
使用log4j2实现日志数据脱敏
需求说明 (1)使用UserDaoImp1类的方法查找用户,并用User类的getUserInfo()方法输出用户信息 ... 实现思路及关键代码 (1)在测试类中调用UserDaoImp类的addUser...(1)使用log4j输出日志信息 (2)查看输出日志信息
下面小编就为大家带来一篇Log4j按级别输出日志到不同文件的实现方法。
2. log4j2 的配置详解,JDBC 配置,CloseableThreadContext 的使用(自定义输出日志文件 例如 logback MDC) 3.logback 的XML配置与使用,MDC的使用,SiftingAppender,DBAppender(c3p0,druid) 详细查看代码:README.md ...
打印日志的在程序中是必不可少的,如果需要将不同的日志打印到不同的地方,则需要定义不同的Appender,然后定义每一个Appender的日志级别、打印形式和日志的输出路径,下面看一个示例吧
log4j 日志服务器 一个系统可能有多个子系统组成,这些子系统都有自己的日志,并且运行在不同的操作系统和主机上,收集这些日志对运营人员来说也比较困难。 因此决定在平台中采用日志服务器来做到集中日志管理,平台...
(3)使用log4j输出日志信息 2.技能训练 (1)会使用try-catch-finally捕获和处理异常 (2)会使用throw和throws (3)会使用log4j记录日志 3.实践 实践一:使用try-catch进行异常处理 需求说明 (1)使用UserDaoImp...
《log4j-1.2.12.jar commons-logging.jar java项目 定时调度 自定义日志》 log4j算是比较好用的日志操作插件了吧,一般与commons-logging一起使用,一直没时间去搞,现在空出了点儿时间,写了一个定时调度程序,将...
过了时间将原日志文件命名为原文件名后加上log4j.appender.File.DatePattern='.'yyyy-MM-dd-HH对应格式的日期, 注意不能用:和_。 关于DailyRollingFileAppender的使用,参考:...
Log4Jse是一个非常简洁、可定制的Javascript日志输出管理工具,类似Log4J,但是比它简单很多,可以实现自定义日志输出级别、自定义日志输出方式等功能。 示例代码: // Usage: var mylog = Logger.get("app"); mylog...
log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的格式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。本节主要讲述如何将日志信息输入到数据库...
1 Log4J简介 3 2 Log4J实现 3 ...3 日志输出方式实现 8 3.1 应用于控制台 8 3.2 应用于文件 8 3.3 应用于文件回滚 8 3.4 应用于socket 9 3.5 发送日志给邮件 9 3.6 用于数据库 9 3.7 自定义Appender 10
可以灵活配置日志输出的格式,类似于log4j的pattern layout 纲目分类模型,比log4j系列的继承模型更加清晰 多种输出,包括动态文件、静态文件、stdout、stderr、syslog 可以在运行时动态刷新配置,只需要调用函数...
Log4J配置文件实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签等全套功能。
通过初始化servlet,在文件里输出你想要的自定义信息,方便的调试功能,输出任意级别的错误.这是个jsp的日志文件配置
自定义Logger章节四:JCL1. 快速入门2. 原理解析章节五:Slf4j1. 快速入门2. 绑定日志实现3. 桥接旧日志实现4. 原理解析章节六:Logback1. 快速入门2. 配置文件3. logback-access使用章节七:Log4j21. 快速入门2. ...