`

Log4j自定义日志输出格式

    博客分类:
  • java
 
阅读更多

代码人,废话不多,直接上代码

主要重写部分,请关注以下代码和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自定义日志文件名及日志输出格式

    根据项目需要,要求日志文件名及输出的日志内容头为特殊的格式,因此重写了log4j的一些方法,如要求的格式和项目不同,可根据示例参考进行再次的修改

    kettle使用log4j管理输出日志

    参照了几个网上大神配置,部分教程的描述有误,最终调试完成,可以实现kettle日志输出,测试版本...需要替换的文件为,Kettle的程序目录下data-integration-6.0\plugins\kettle5-log4j-plugin中有一个log4j.xml文件。

    log4j多文件输出打印

    log4j、日志输出、自定义日志、多文件输出。

    log4j输出多个自定义路径的日志文件小例子

    本工程主要实现log4j输出多个自定义路径的日志文件,为方便大家使用

    使用log4j2实现日志数据脱敏

    使用log4j2实现日志数据脱敏

    log4j输出日志信息

    需求说明 (1)使用UserDaoImp1类的方法查找用户,并用User类的getUserInfo()方法输出用户信息 ... 实现思路及关键代码 (1)在测试类中调用UserDaoImp类的addUser...(1)使用log4j输出日志信息 (2)查看输出日志信息

    Log4j按级别输出日志到不同文件的实现方法

    下面小编就为大家带来一篇Log4j按级别输出日志到不同文件的实现方法。

    log4j,log4j2,logback 日志插件的使用例子

    2. log4j2 的配置详解,JDBC 配置,CloseableThreadContext 的使用(自定义输出日志文件 例如 logback MDC) 3.logback 的XML配置与使用,MDC的使用,SiftingAppender,DBAppender(c3p0,druid) 详细查看代码:README.md ...

    java自定义日志输出文件(log4j日志文件输出多个自定义日志文件)

    打印日志的在程序中是必不可少的,如果需要将不同的日志打印到不同的地方,则需要定义不同的Appender,然后定义每一个Appender的日志级别、打印形式和日志的输出路径,下面看一个示例吧

    log4j 日志服务器

    log4j 日志服务器 一个系统可能有多个子系统组成,这些子系统都有自己的日志,并且运行在不同的操作系统和主机上,收集这些日志对运营人员来说也比较困难。 因此决定在平台中采用日志服务器来做到集中日志管理,平台...

    方法抛出的异常处理 (2)修改UserDaoImp1类,要求用户id不能修改,修改则抛出异常 使用log4j输出日志信息

    (3)使用log4j输出日志信息 2.技能训练 (1)会使用try-catch-finally捕获和处理异常 (2)会使用throw和throws (3)会使用log4j记录日志 3.实践 实践一:使用try-catch进行异常处理 需求说明 (1)使用UserDaoImp...

    log4j java项目案例

    《log4j-1.2.12.jar commons-logging.jar java项目 定时调度 自定义日志》 log4j算是比较好用的日志操作插件了吧,一般与commons-logging一起使用,一直没时间去搞,现在空出了点儿时间,写了一个定时调度程序,将...

    log4j使用实战

    过了时间将原日志文件命名为原文件名后加上log4j.appender.File.DatePattern='.'yyyy-MM-dd-HH对应格式的日期, 注意不能用:和_。 关于DailyRollingFileAppender的使用,参考:...

    Javascript日志输出管理工具Log4Jse.zip

    Log4Jse是一个非常简洁、可定制的Javascript日志输出管理工具,类似Log4J,但是比它简单很多,可以实现自定义日志输出级别、自定义日志输出方式等功能。 示例代码: // Usage: var mylog = Logger.get("app"); mylog...

    Log4j写入数据库详解

    log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的格式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。本节主要讲述如何将日志信息输入到数据库...

    log4j参考手册

    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

    zlog---比log4c更牛的c语言日志库

    可以灵活配置日志输出的格式,类似于log4j的pattern layout 纲目分类模型,比log4j系列的继承模型更加清晰 多种输出,包括动态文件、静态文件、stdout、stderr、syslog 可以在运行时动态刷新配置,只需要调用函数...

    LOG4J配置全接触

    Log4J配置文件实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签等全套功能。

    log4j日志文件配置

    通过初始化servlet,在文件里输出你想要的自定义信息,方便的调试功能,输出任意级别的错误.这是个jsp的日志文件配置

    java日志框架视频教程

    自定义Logger章节四:JCL1. 快速入门2. 原理解析章节五:Slf4j1. 快速入门2. 绑定日志实现3. 桥接旧日志实现4. 原理解析章节六:Logback1. 快速入门2. 配置文件3. logback-access使用章节七:Log4j21. 快速入门2. ...

Global site tag (gtag.js) - Google Analytics