Java日志

Java日志

JDK日志

日志级别

级别SEVEREWARNINGINFOCONFIGFINEFINERFINEST
调用方法severe()warning()info()config()fine()finer()finest()
含义严重警告信息配置良好较好最好

示例

package cn.chenzhen;


import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.*;

public class MainApplication {
    private static final Logger logger = Logger.getLogger(MainApplication.class.getName());
    static {
        // 拿到根节点日志
        Logger parent = logger.getParent();
        Handler handler = parent.getHandlers()[0];
        //默认输出到控制台  需要修改一下输出格式
        // 创建一个输出格式
        Formatter formatter = new Formatter() {
            private final String dataPatter = "yyyy-MM-dd HH:mm:ss:SSS";

            @Override
            public String format(LogRecord record) {
                SimpleDateFormat format = new SimpleDateFormat(dataPatter);
                // 设置输出格式
                return String.format("%s %-7s %s %s %s\n",
                        format.format(new Date(record.getMillis())),
                        record.getLevel().getName(),
                        record.getSourceClassName(),
                        record.getSourceMethodName(),
                        record.getMessage());
            }
        };
        // 设置输出格式
        handler.setFormatter(formatter);

        try {
            // 如果保存到指定文件夹里面 必须保证文件夹存在
            new File("logs").mkdirs();
            /*
            	/	本地路径名分隔符
                %t	系统临时目录
                %h	系统属性user.home的值
                %g	用于区分旋转日志的代数
                %u	是解决冲突的唯一数字
                %	转换为一个百分号 %
            */
            // 输出到文件

            FileHandler fileHandler = new FileHandler("logs/log_%g.log");
            fileHandler.setFormatter(formatter);
            parent.addHandler(fileHandler);


        } catch (IOException e) {
            e.printStackTrace();
        }


    }
    public static void main(String[] args) {
        logger.finest("日志 finest");
        logger.finer("日志 finer");
        logger.fine("日志 fine");
        logger.config("日志 config");
        logger.info("日志 info");
        logger.warning("日志 warning");
        logger.severe("日志 severe");
    }
}

Log4J 日志

依赖:

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局)。这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松地记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。

日志级别

从小到大 TRACE 《 FATAL

方法级别
TRACE查出
DEBUG调试
INFO信息
WARN警告
ERROR错误
FATAL致命的

Appenders 日志处理器

作用
org.apache.log4j.ConsoleAppender吧日志输出到 控制台
org.apache.log4j.FileAppender吧日志输出到 文件
org.apache.log4j.DailyRollingFileAppender每天产生一个日志文件
org.apache.log4j.RollingFileAppender文件大小到达指定尺寸的时候产生一个新的文件
org.apache.log4j.WriterAppender将日志信息以流格式发送到任意指定的地方

Layouts 日志输出格式处理器

作用
org.apache.log4j.HTMLLayout输出日式 以HTML表格形式布局
org.apache.log4j.PatternLayout可以灵活地指定布局模式
org.apache.log4j.SimpleLayout输出日式 包含日志信息的级别和信息字符串
org.apache.log4j.TTCCLayout输出日式 包含日志产生的时间、线程、类别等信息

日志格式

参数说明
%c日志消息所在类名
%c{2}日志消息所在类名 设置输出最大层级数
%20c若名字空间长度小于20,则左边用空格填充
%-20c若名字空间长度小于20,则右边用空格填充
%.30c若名字空间长度超过30,截去多余字符
%20.30c若名字空间长度小于20,则左边用空格填充;若名字空间长度超过30,截去多余字符
%-20.30c若名字空间长度小于20,则右边用空格填充;若名字空间长度超过30,截去多余字符
%C列出调用logger的类的全名包含包路径
%C{1}设置输出最大层级数 只输出类名
%d显示日志记录时间,{<日期格式>} 自定义格式:%d{yyyy/MM/dd HH:mm:ss,SSS}
%F显示调用logger的源文件名 如:%F XXX.java
%l输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数
%L显示调用logger的代码行
%m显示输出消息
%M显示调用logger的方法名
%n当前平台下的换行符 %n Windows平台下表示\r\n UNIX平台下表示\n
%p显示该条日志的优先级
%r显示从程序启动时到记录该条日志时已经经过的毫秒数
%t输出产生该日志事件的线程名
%x按NDC(Nested Diagnostic Context,线程堆栈)顺序输出日志
%%显示一个百分号 %%

输出日志到控制台

配置文件设置

文件名:log4j.properties

# 创建日志 多个使用 , 隔开 日志名自定义
# 第一个是日志级别
log4j.rootLogger=ALL,CONSOLE

# 输出日志到控制台
# 设置自定义日志 类
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
# 设置日志输出都哪里
log4j.appender.CONSOLE.Target=System.out
# 设置日志输出格式处理类
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] %d(%r) [%t] %l: %m %x %n
输出日志
import org.apache.log4j.Logger;

public class MainLog4jApplication {
    // 创建日志
    private static final Logger logger = Logger.getLogger(MainLog4jApplication.class);
    public static void main(String[] args) {
        // 打印日志
        logger.debug("日志 debug");
        logger.info("日志 info");
        logger.warn("日志 warn");
        logger.error("日志 error");
    }
}

日志配置

配置 log4j.properties 文件

Logger 配置根
log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
log4j.additivity.org.apache=false:表示Logger不会在父Logger的appender里输出,默认为true。
# level :设定日志记录的最低级别,可设的值有OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别,Log4j建议只使用中间四个级别。通过在这里设定级别,您可以控制应用程序中相应级别的日志信息的开关,比如在这里设定了INFO级别,则应用程序中所有DEBUG级别的日志信息将不会被打印出来。
# appenderName:就是指定日志信息要输出到哪里。可以同时指定多个输出目的地,用逗号隔开。
# 例如:log4j.rootLogger=INFO,A1,B2,C3
appender 配置日志信息输出目的地

语法:log4j.appender.appenderName = className

appenderName:自定义appderName,在log4j.rootLogger设置中使用;
className:可设值如下:
    (1)org.apache.log4j.ConsoleAppender				控制台
    (2)org.apache.log4j.FileAppender				文件
    (3)org.apache.log4j.DailyRollingFileAppender	每天产生一个日志文件
    (4)org.apache.log4j.RollingFileAppender			文件大小到达指定尺寸的时候产生一个新的文件)
    (5)org.apache.log4j.WriterAppender				将日志信息以流格式发送到任意指定的地方

# ---------- 配置appender ----------
log4j.rootLogger=ALL,appenderName1,appenderName2,appenderName3,appenderName4,appenderName5
log4j.appender.appenderName1=org.apache.log4j.ConsoleAppender
log4j.appender.appenderName2=org.apache.log4j.FileAppender
log4j.appender.appenderName3=org.apache.log4j.DailyRollingFileAppender
log4j.appender.appenderName4=org.apache.log4j.RollingFileAppender
log4j.appender.appenderName5=org.apache.log4j.WriterAppender
ConsoleAppender 选项
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Target=System.err:默认值是System.out。

# --------------- 日志输出到控制台 配置  ---------------
log4j.rootLogger=ALL,CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=ALL
log4j.appender.CONSOLE.ImmediateFlush=true
log4j.appender.CONSOLE.Target=System.out
# 设置日志输出格式处理类
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] %d(%r) [%t] %.50l: %m %x %n

FileAppender选项
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Append=false:true 表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true。
File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件中。

# --------------- 日志保存到文件 配置  ---------------
log4j.rootLogger=ALL,FILE
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.Threshold=ALL
log4j.appender.FILE.ImmediateFlush=true
log4j.appender.FILE.Append=true
log4j.appender.FILE.File=./logs/data_log.log
# 设置日志输出格式处理类
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.FILE.layout.ConversionPattern=[%-5p] %d(%r) [%t] %.50l: %m %x %n
DailyRollingFileAppender选项
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Append=false:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true。
File=D:/logs/logging.log4j:指定当前消息输出到logging.log4j文件中。
DatePattern='.'yyyy-MM:每月滚动一次日志文件,即每月产生一个新的日志文件。当前月的日志文件名为logging.log4j,
另外,也可以指定按周、天、时、分等来滚动日志文件,对应的格式如下:
    1)'.'yyyy-MM:每月
    2)'.'yyyy-ww:每周
    3)'.'yyyy-MM-dd:每天
    4)'.'yyyy-MM-dd-a:每天两次
    5)'.'yyyy-MM-dd-HH:每小时
    6)'.'yyyy-MM-dd-HH-mm:每分钟

Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Append=false:true 表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true。
File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件中。

# --------------- 日志保存到文件 根据日期动态滚动 配置  ---------------
log4j.rootLogger=ALL,DRFILE
log4j.appender.DRFILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRFILE.Threshold=ALL
log4j.appender.DRFILE.ImmediateFlush=true
log4j.appender.DRFILE.Append=true
log4j.appender.DRFILE.File=./logs/data_log.log
log4j.appender.DRFILE.DatePattern='.'yyyyMMddHHmm
# 设置日志输出格式处理类
log4j.appender.DRFILE.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.DRFILE.layout.ConversionPattern=[%-5p] %d(%r) [%t] %.50l: %m %x %n
RollingFileAppender选项
Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG。
ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true。
Append=false:true表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true。
File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件中。
MaxFileSize=100KB:后缀可以是KB, MB 或者GB。在日志文件到达该大小时,将会自动滚动,即将原来的内容移到logging.log4j.1文件中。
MaxBackupIndex=2:指定可以产生的滚动文件的最大数,例如,设为2则可以产生logging.log4j.1,logging.log4j.2两个滚动文件和一个logging.log4j文件。


# --------------- 日志保存到文件 根据文件大小动态滚动 配置  ---------------
log4j.rootLogger=ALL,RFILE
log4j.appender.RFILE=org.apache.log4j.RollingFileAppender
log4j.appender.RFILE.Threshold=ALL
log4j.appender.RFILE.ImmediateFlush=true
log4j.appender.RFILE.Append=true
log4j.appender.RFILE.File=./logs/data_log.log
log4j.appender.RFILE.MaxFileSize=10KB
log4j.appender.RFILE.MaxBackupIndex=100
# 设置日志输出格式处理类
log4j.appender.RFILE.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.RFILE.layout.ConversionPattern=[%-5p] %d(%r) [%t] %.50l: %m %x %n


自定义 实现滚动文件夹

复制DailyRollingFileAppender类

dirPattern 文件夹滚动规则

log4j.rootLogger=ALL,MDRFILE
# --------------- 自定义日志保存到文件 文件夹和文件通过日期动态滚动 配置  ---------------

log4j.appender.MDRFILE=cn.chenzhen.logger.DirectoryAndDailyRollingFileAppender
log4j.appender.MDRFILE.Threshold=ALL
log4j.appender.MDRFILE.ImmediateFlush=true
log4j.appender.MDRFILE.Append=true
log4j.appender.MDRFILE.File=./logs/log.log
log4j.appender.MDRFILE.DatePattern=yyyyMMddHHmm
# 设置文件夹滚动规则
log4j.appender.MDRFILE.dirPattern=yyyyMMddHHmm
# 设置日志输出格式处理类
log4j.appender.MDRFILE.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.MDRFILE.layout.ConversionPattern=[%-5p] %d(%r) [%t] %.50l: %m %x %n
package cn.chenzhen.logger;

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.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

/**
 * 动态创建文件和文件夹
 */
public class DirectoryAndDailyRollingFileAppender 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";
    // 文件夹规则
    private String dirPattern = "yyyyMMdd";

    /**
     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 DirectoryAndDailyRollingFileAppender() {
    }

    /**
     Instantiate a <code>DirectoryAndDailyRollingFileAppender</code> and open the
     file designated by <code>filename</code>. The opened filename will
     become the ouput destination for this appender.

     */
    public DirectoryAndDailyRollingFileAppender (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);
            // 设置文件夹格式
            SimpleDateFormat psdf = new SimpleDateFormat(dirPattern);
            int type = computeCheckPeriod();
            printPeriodicity(type);
            rc.setType(type);
            File file = new File(fileName);
            // 设置文件名
            scheduledFilename = file.getParentFile().getPath()+"/"+ psdf.format(new Date(file.lastModified())) + "/" + sdf.format(new Date(file.lastModified())) + file.getName();
            // 创建文件夹 如果文件夹不存在 写入日志会报错
            new File(scheduledFilename).getParentFile().mkdirs();
            System.out.println("得到新文件名:" + scheduledFilename);
        } 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 DirectoryAndDailyRollingFileAppender 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);
            }
        }
        super.subAppend(event);
    }

    public String getDirPattern() {
        return dirPattern;
    }

    public void setDirPattern(String dirPattern) {
        this.dirPattern = dirPattern;
    }
}

/**
 *  RollingCalendar is a helper class to DirectoryAndDailyRollingFileAppender.
 *  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 = DirectoryAndDailyRollingFileAppender.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 DirectoryAndDailyRollingFileAppender.TOP_OF_MINUTE:
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.MINUTE, 1);
                break;
            case DirectoryAndDailyRollingFileAppender.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 DirectoryAndDailyRollingFileAppender.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 DirectoryAndDailyRollingFileAppender.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 DirectoryAndDailyRollingFileAppender.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 DirectoryAndDailyRollingFileAppender.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.rootLogger=DEBUG,console,dailyFile,im,MDRFILE
log4j.additivity.org.apache=true
# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

# 日志文件(logFile)
log4j.appender.logFile=org.apache.log4j.FileAppender
log4j.appender.logFile.Threshold=DEBUG
log4j.appender.logFile.ImmediateFlush=true
log4j.appender.logFile.Append=true
log4j.appender.logFile.File=D:/logs/log.log4j
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

# 回滚文件(rollingFile)
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.Threshold=DEBUG
log4j.appender.rollingFile.ImmediateFlush=true
log4j.appender.rollingFile.Append=true
log4j.appender.rollingFile.File=D:/logs/log.log4j
log4j.appender.rollingFile.MaxFileSize=200KB
log4j.appender.rollingFile.MaxBackupIndex=50
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

# 定期回滚日志文件(dailyFile)
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.Threshold=DEBUG
log4j.appender.dailyFile.ImmediateFlush=true
log4j.appender.dailyFile.Append=true
log4j.appender.dailyFile.File=D:/logs/log.log4j
log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

# 应用于socket
log4j.appender.socket=org.apache.log4j.RollingFileAppender
log4j.appender.socket.RemoteHost=localhost
log4j.appender.socket.Port=5001
log4j.appender.socket.LocationInfo=true
# Set up for Log Factor 5
log4j.appender.socket.layout=org.apache.log4j.PatternLayout
log4j.appender.socket.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000

# 发送日志到指定邮件
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
log4j.appender.mail.Threshold=FATAL
log4j.appender.mail.BufferSize=10
log4j.appender.mail.From = xxx@mail.com
log4j.appender.mail.SMTPHost=mail.com
log4j.appender.mail.Subject=Log4J Message
log4j.appender.mail.To= xxx@mail.com
log4j.appender.mail.layout=org.apache.log4j.PatternLayout
log4j.appender.mail.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

# 应用于数据库
log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.database.URL=jdbc:mysql://localhost:3306/test
log4j.appender.database.driver=com.mysql.jdbc.Driver
log4j.appender.database.user=root
log4j.appender.database.password=
log4j.appender.database.sql=INSERT INTO LOG4J (Message) VALUES('=[%-5p] %d(%r) --> [%t] %l: %m %x %n')
log4j.appender.database.layout=org.apache.log4j.PatternLayout
log4j.appender.database.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

# 自定义Appender
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@cybercorlin.net
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n


# --------------- 自定义日志保存到文件 文件夹和文件通过日期动态滚动 配置  ---------------

log4j.appender.MDRFILE=cn.chenzhen.logger.DirectoryAndDailyRollingFileAppender
log4j.appender.MDRFILE.Threshold=ALL
log4j.appender.MDRFILE.ImmediateFlush=true
log4j.appender.MDRFILE.Append=true
log4j.appender.MDRFILE.File=./logs/log.log
log4j.appender.MDRFILE.DatePattern=yyyyMMddHHmm
# 设置文件夹滚动规则
log4j.appender.MDRFILE.dirPattern=yyyyMMddHHmm
# 设置日志输出格式处理类
log4j.appender.MDRFILE.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.MDRFILE.layout.ConversionPattern=[%-5p] %d(%r) [%t] %.50l: %m %x %n

给不同包路径配置不同日志

语法:log4j.logger.包[.类]= DEBUG, test

# --------------- 给不同包配置 或者 类 不同日志文件  ---------------
# 语法:log4j.logger.包=日志级别,日志处理器
# 语法:log4j.logger.包.类名=日志级别,日志处理器
log4j.logger.cn.chenzhen=ALL,CNLOGGER

log4j.appender.CNLOGGER=org.apache.log4j.FileAppender
log4j.appender.CNLOGGER.Threshold=ALL
log4j.appender.CNLOGGER.ImmediateFlush=true
log4j.appender.CNLOGGER.Append=true
log4j.appender.CNLOGGER.File=./logs/cn/data_log.log
# 设置日志输出格式处理类
log4j.appender.CNLOGGER.layout=org.apache.log4j.PatternLayout
# 设置日志输出格式
log4j.appender.CNLOGGER.layout.ConversionPattern=[%-5p] %d(%r) [%t] %.50l: %m %x %n

log4j2

导入依赖

<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>

日志级别

日志级别作用
trace追踪,就是程序推进一下,可以写个trace输出
debug调试,一般作为最低级别,trace基本不用
info输出重要的信息,使用较多
warn警告,有些信息不是错误信息,但也要给程序员一些提示
error错误信息。用的也很多
fatal致命错误。级别较高,这种级别不用调试了,重写吧……

日志处理器

作用
org.apache.logging.log4j.core.appender.ConsoleAppender输出日志到控制台
org.apache.logging.log4j.core.appender.FileAppender输出日志到文件
org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender输出日志到数据库
org.apache.logging.log4j.core.appender.HttpAppender输出日志到 HTTP请求
org.apache.logging.log4j.core.appender.RollingFileAppender输出日志到文件 通过日期时间、大小动态滚动文件

日志输出格式处理器 日志布局

作用
org.apache.logging.log4j.core.layout.PatternLayout自定义输出日志格式
org.apache.logging.log4j.core.layout.HtmlLayout输出日志格式为HTML
org.apache.logging.log4j.core.layout.JsonLayout输出日志格式为JSON
org.apache.logging.log4j.core.layout.XmlLayout输出日志以为XML
org.apache.logging.log4j.core.layout.YamlLayout输出日志以为YAML

日志格式

参数说明
%c{precision} = %logger{precision}输出发布日志事件的日志程序的名称
%C{precision} = %class{precision}输出发出日志记录请求的调用者的完全限定类名,可能会影响性能,谨慎使用
%d{pattern} = %date{pattern}输出日志事件的日期。日期转换说明符后面可以跟一组大括号,其中包含每个SimpleDateFormat的日期和时间模式字符串
%enc{pattern}{[HTML|XML|JSON|CRLF]} = %encode{pattern}{[HTML|XML|JSON|CRLF]}对适合用特定标记语言输出的特殊字符进行编码和转义。默认情况下如果只指定了一个选项,它将对HTML进行编码。第二个选项用于指定应该使用哪种编码格式。此转换器特别适用于对用户提供的数据进行编码,这样输出数据就不会写得不正确或不安全
%ex = %exception = %throwable输出绑定到日志事件的可抛出跟踪,默认情况下,这将输出完整的跟踪,就像调用Throwable. printstacktrace()时通常会看到的那样
%F = %file输出发出日志记录请求的文件名。生成文件信息(位置信息)是一项昂贵的操作,可能会影响性能,请谨慎使用
%highlight{pattern}{style}根据当前事件的日志级别将ANSI颜色添加到所包含模式的结果中。(见Jansi配置。)
%l = %location输出生成日志事件的调用者的位置信息。位置信息取决于JVM实现,但通常由调用方法的完全限定名、调用者源文件名和括号之间的行号组成。生成位置信息是一项昂贵的操作,可能会影响性能,请谨慎使用
%L = %line上面location功能的简略版,仅仅输出发出日志请求的行号。同样生成行号信息可能会影响性能,请谨慎使用
%m{nolookups}{ansi} = %msg{nolookups}{ansi} = %message{nolookups}{ansi}输出应用程序提供的与日志事件关联的消息
%M = %method输出发出日志请求的方法名。生成调用者的方法名(位置信息)是一项昂贵的操作,可能会影响性能,请谨慎使用
%maxLen = %maxLength输出评估模式的结果并截断结果。如果长度大于20,则输出将包含一个拖尾省略号。如果提供的长度无效,则使用默认值100。示例语法:%maxLen{%p: %c{1} - %m%notEmpty{=>%ex{short}}}{160}将被限制为160个字符,后面加一个省略号。另一个例子:%maxLen{%m}{20}将被限制为20个字符,并且没有拖尾省略号
%n输出平台相关的行分隔符字符。与使用不可移植的行分隔符字符串(如“\n”或“\r\n”)相比,这个转换字符提供了几乎相同的性能。因此,它是指定行分隔符的首选方法
%N = %nano在创建日志事件时输出System.nanoTime()的结果
%pid{[defaultValue]} = %processId{[defaultValue]}如果底层平台支持,则输出进程ID。如果平台不支持进程id,可以指定一个可选的默认值来显示
%p = %evel输出日志事件的级别
%r = %relative输出从JVM启动到日志事件创建的毫秒数
%replace{pattern}{regex}{substitution}将正则表达式’regex’的出现替换为对模式求值后字符串中的’替换’。例如,“%replace{%msg}{\s}{}”将删除事件消息中包含的所有空格。模式可以任意复杂,特别是可以包含多个转换关键字。例如,“%替换{%logger %msg}{\。}{/}将用正斜杠替换日志记录器或事件消息中的所有点
%sn = %sequenceNumber包含将在每个事件中递增的序列号。计数器是一个静态变量,因此它只在共享相同转换器类对象的应用程序中是唯一的
%T = %tid = %threadId输出生成日志事件的线程ID
%t = %tn = %thread = %threadName输出生成日志事件的线程名称
%tp = %threadPriority输出生成日志事件的线程的优先级
%fqcn输出记录器的完全限定类名
%endOfBatch输出日志事件的EndOfBatch状态,为“true”或“false”
u{“RANDOM” |“TIME”} = uuid包括一个随机的或基于时间的UUID。基于时间的UUID是一个1型UUID,可以产生高达每毫秒10000独特的id,将使用每个主机的MAC地址,并试图确保唯一性跨多个jvm和/或类加载器在同一个主机上0到16384之间的一个随机数将与每个UUID生成类的实例相关联,包括在每一个基于时间的UUID生成。因为基于时间的uuid包含MAC地址和时间戳,所以应该小心使用它们,因为它们可能会导致安全漏洞
%%输出一个百分比符号

日志格式长度限制 截取

规则实际输出值
%c{1}org.apache.commons.FooFoo
%c{2}org.apache.commons.Foocommons.Foo
%c{10}org.apache.commons.Fooorg.apache.commons.Foo
%c{-1}org.apache.commons.Fooapache.commons.Foo
%c{-2}org.apache.commons.Foocommons.Foo
%c{-10}org.apache.commons.Fooorg.apache.commons.Foo
%c{1.}org.apache.commons.Fooo.a.c.Foo
%c{1.1…}org.apache.commons.test.Fooo.a…Foo
%c{.}org.apache.commons.test.Foo…Foo

日志长度占位符 填充空格

格式修饰符对齐方式最小宽度最大宽度说明
%20c右对齐20不足20个字符则在数值前面用空格补足,超过20个字符则保留原信息。
%-20c左对齐20同上。
%.30cNA30如果信息超过30个字符,则只保留最后30个字符。
%20.30c右对齐2030不足20个字符则在信息前面用空格补足,超过30个字符则只保留最后30个字符。
%-20.30c左对齐2030同上。
%-20.-30c左对齐2030不足20个字符则在信息前面用空格补足,超过30个字符则只保留前面30个字符。

日志过滤器

Accept 表示日志事件会被立即处理,不会调用其他 Filter;
Deny 表示日志事件被立即忽略并不再经过其他过滤器;
Neutral 表示日志事件将传递给其他 Filter,如果没有其他 Filter,则事件将会被处理。

参数类型描述
levelString匹配的可用的日志级别,可以为 OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE 、ALL 之一
onMatchString当日志级别匹配时匹配时执行的过滤动作,可以为 ACCEPT(接受)、DENY(否认)、NEUTRAL(中立) 之一,默认为 NEUTRAL
onMismatchString当日志级别不匹配时执行的过滤动作,可以为ACCEPT(接受)、DENY(否认)、NEUTRAL(中立)之一,默认为 DENY

调用日志

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class MainLog4j2Application {
    private static final Logger logger =  LogManager.getLogger(MainLog4j2Application.class);
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            logger.debug("日志 debug" + i);
            logger.info("日志 info" + i);
            logger.warn("日志 warn" + i);
            logger.error("日志 error" + i);
        }
    }
}

输出日志到控制台

<?xml version="1.0" encoding="UTF-8" ?>
<!-- status 接收的日志级别 -->
<Configuration status="ALL">
    <Appenders>
        <!-- 输出到控制台
         name 随便起
         target 使用那种方式输出:
            SYSTEM_OUT
            SYSTEM_ERR
         -->
        <Console name="Console" target="SYSTEM_OUT">
            <!--【可选】  只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 设置输出规则 -->
            <PatternLayout pattern="[%-5level] %d (%r) %t %l %m %n"></PatternLayout>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="ALL">
            <!-- 引用 上面定义的日志处理器
             additivity="false" 禁用这种叠加继承 防止控制台重复打印相同日志
             -->
            <AppenderRef ref="Console" additivity="false"></AppenderRef>
        </Root>
    </Loggers>
</Configuration>

输出日志到文件

<?xml version="1.0" encoding="UTF-8" ?>
<!-- status 接收的日志级别 -->
<Configuration status="ALL">
    <Appenders>
        <!-- 配置 日志输出到文件 -->
        <!--
            type="File" 日志处理器
            name="FILE" 名字随便起
            append="true" 追加内容模式
        -->
        <File type="File" name="FILE" fileName="logs/log.log" append="true">
            <!--【可选】  只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 设置输出规则 -->
            <PatternLayout pattern="[%-5level] %d (%r) %t %l %m %n"></PatternLayout>
        </File>
    </Appenders>
    <Loggers>
        <Root level="ALL">
            <!-- 引用 上面定义的日志处理器
             additivity="false" 禁用这种叠加继承 防止台重复打印相同日志
             -->
            <AppenderRef ref="FILE"></AppenderRef>
        </Root>
    </Loggers>
</Configuration>

日志滚动 根据时间、大小

<?xml version="1.0" encoding="UTF-8" ?>
<!-- status 接收的日志级别 -->
<Configuration status="ALL">
    <Appenders>
        <!-- 文件动态滚动 可以根据时间 大小
         filePattern 文件位置 时间滚动就是根据这个来滚动的
         -->
        <RollingFile name="ROLLINGFILE" fileName="logs/log4j2/log.log"
                     filePattern="logs/$${date:yyyyMMddHHmm}/%d{yyyyMMddHHmm}-%i.log"
        >
            <!--  只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 设置输出规则 -->
            <PatternLayout pattern="[%-5level] %d (%r) %t %l %m %n"></PatternLayout>
            <Policies>
                <!-- 每1天更新一次,此处查阅网上和官方示例中,都是以小时出现,我测试是以天为单位。(官方文档中说明按item类型是否是小时,但没找到在哪里设置item类型)另有其他各类型策略,请参阅官方文档 -->
                <!--
                    modulate="true" 是否校准时间
                    interval="1"    日志滚动间隔 一般为1 默认为1 表示时间加1 就滚动 可以看做步长
                 -->
                <TimeBasedTriggeringPolicy modulate="true"
                                           interval="1" />
                <!-- 使用Cron 表达式 每 5s 翻滚一次 -->
                <!--<CronTriggeringPolicy schedule="0/5 * * * * ?"/>-->
                <!-- 此处为每个文件大小策略限制,使用它一般会在文件中filePattern采用%i模式 -->
                 <SizeBasedTriggeringPolicy size="1KB" />
            </Policies>
            <!--保存日志文件个数-->
            <DefaultRolloverStrategy max="10"/>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="ALL">
            <!-- 引用 上面定义的日志处理器
             additivity="false" 禁用这种叠加继承 防止控制台重复打印相同日志
             -->
            <AppenderRef ref="ROLLINGFILE"></AppenderRef>
        </Root>
    </Loggers>
</Configuration>

定期清理日志文件

<?xml version="1.0" encoding="UTF-8" ?>
<!-- status 接收的日志级别 -->
<Configuration status="ALL">
    <Appenders>
        <!-- 文件动态滚动 可以根据时间 大小
         filePattern 文件位置 时间滚动就是根据这个来滚动的
         -->
        <RollingFile name="ROLLINGFILE" fileName="logs/log4j2/log.log"
                     filePattern="logs/$${date:yyyyMMddHHmm}/%d{yyyyMMddHHmm}-%i.log"
        >
            <!--  只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 设置输出规则 -->
            <PatternLayout pattern="[%-5level] %d (%r) %t %l %m %n"></PatternLayout>
            <Policies>
                <!-- 每1天更新一次,此处查阅网上和官方示例中,都是以小时出现,我测试是以天为单位。(官方文档中说明按item类型是否是小时,但没找到在哪里设置item类型)另有其他各类型策略,请参阅官方文档 -->
                <!--
                    modulate="true" 是否校准时间
                    interval="1"    日志滚动间隔 一般为1 默认为1 表示时间加1 就滚动 可以看做步长
                 -->
                <TimeBasedTriggeringPolicy modulate="true"
                                           interval="1" />
                <!-- 此处为每个文件大小策略限制,使用它一般会在文件中filePattern采用%i模式 -->
                 <SizeBasedTriggeringPolicy size="1KB" />
            </Policies>
            <!--保存日志文件个数 max默认为 7 表示最大保存7位文件 也就是设置 %i 的最大值 超过了会自动删除第一个文件-->
            <DefaultRolloverStrategy max="5">
                <!-- 配置额外删除任务 比如删除缓存文件之类的
                    basePath="logs/" 删除Base路径
                     maxDepth="5"   删除文件路径深度
                 -->
                <Delete basePath="logs/tmp/" maxDepth="5">
                    <!-- 配置文件名规则 -->
                    <IfFileName glob="tmp*.log" />
                    <!-- 删除超过指定最后修改时间的文件  -->
                    <IfLastModified age="30d" />
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>

    </Appenders>
    <Loggers>
        <Root level="ALL">
            <!-- 引用 上面定义的日志处理器
             additivity="false" 禁用这种叠加继承 防止控制台重复打印相同日志
             -->
            <AppenderRef ref="ROLLINGFILE"></AppenderRef>
        </Root>
    </Loggers>
</Configuration>

Logback

导入依赖

<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

日志级别

日志级别作用
trace追踪,就是程序推进一下,可以写个trace输出
debug调试,一般作为最低级别,trace基本不用
info输出重要的信息,使用较多
warn警告,有些信息不是错误信息,但也要给程序员一些提示
error错误信息。用的也很多

日志处理器

作用
ch.qos.logback.core.ConsoleAppender输出日志到控制台
ch.qos.logback.core.FileAppender输出日志到文件
ch.qos.logback.core.RollingFileAppender输出日志到文件 动态滚动日志 支持时间、文件大小进行滚动

日志格式处理器

作用
ch.qos.logback.classic.PatternLayout自定义输出日志格式
ch.qos.logback.classic.html.HTMLLayout输出日志格式为HTML格式
ch.qos.logback.classic.log4j.XMLLayout输出日志格式为xml格式

日志格式 占位符

占位符作用
%c = %log = %logger输出日志的logger名
%c = %class输出执行记录请求的调用者的全限定名
%contextName = %cn输出上下文名称
%d = %date输出日志的打印日志
%F = %file输出执行记录请求的java源文件名
%caller输出生成日志的调用者的位置信息,整数选项表示输出信息深度
%L = %line输出执行日志请求的行号
%m = %msg = %message输出应用程序提供的信息
%M = %method输出执行日志请求的方法名
%n输出平台先关的分行符
%p = %le = %level输出日志级别
%r = %relative输出从程序启动到创建日志记录的时间,单位毫秒
%t = %thread输出产生日志的线程名
%replace§{r,t}替换内容 p 为日志内容,r 是正则表达式,将p 中符合r 的内容替换为t

日志输出包名长度限制 截取

符号内容实际输出内容
%loggermainPackage.sub.sample.BarmainPackage.sub.sample.Bar
%logger{0}mainPackage.sub.sample.BarBar
%logger{5}mainPackage.sub.sample.Barm.s.s.Bar
%logger{10}mainPackage.sub.sample.Barm.s.s.Bar
%logger{15}mainPackage.sub.sample.Barm.s.sample.Bar
%logger{16}mainPackage.sub.sample.Barm.sub.sample.Bar
%logger{26}mainPackage.sub.sample.BarmainPackage.sub.sample.Bar

日志长度内容限制、截取

符号左对齐最小字符最大长度描述
%20loggerfalse20none内容长度小于20个字符,在左侧填充空格。
%-20loggertrue20none长度小于20个字符,在右键填充空格
%.30loggerNAnone30内容超过30个字符,则从开头(左边)截断。
%.-30loggerNAnone30如果记录器名称超过30个字符,则从结束(右边)处截断。
%20.30loggerfalse2030内容短于20个字符,则左空格为空格。但是,如果记录器名称超过30个字符,则从开头(左边)截断。
%-20.30loggertrue2030内容少于20个字符,则右键填充空格。但是,如果记录器名称超过30个字符,则从开始(左边)截断

列子:

符号内容实际输出内容
%20.20loggermain.Namemain.Name
%-20.20loggermain.Namemain.Name
%10.10loggermain.foo.foo.bar.Nameo.bar.Name
%10.-10loggermain.foo.foo.bar.Namemain.foo.f

输出日志到控制台

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    
    <!-- 设置格式化输出格式 -->
    <property name="pattern" value="%d{yyyy-MM-dd:HH:mm:ss.SSS} %r [%thread] %-5level %c %M %L  %msg%n"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 字符串System.out(默认)或者System.err -->
        <target>System.out</target>
        <!-- 对记录事件进行格式化 -->
        <encoder>
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <root level="TRACE">
        <appender-ref ref="console"/>
    </root>
</configuration>

输出日志到文件

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!-- 设置格式化输出格式 -->
    <property name="pattern" value="%d{yyyy-MM-dd:HH:mm:ss.SSS} %r [%thread] %-5level %c %M %L  %msg%n"/>

    <!-- 输出日志到控制台 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 字符串System.out(默认)或者System.err -->
        <target>System.out</target>
        <!-- 对记录事件进行格式化 -->
        <encoder>
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>
    
    <!-- 输出日志到文件 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <!-- 设置文件输出格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- 文件路径 -->
        <file>logs/logback/test.log</file>
    </appender>
    <root level="TRACE">
        <appender-ref ref="console"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

日志滚动 根据时间、大小

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!-- 设置格式化输出格式 -->
    <property name="pattern" value="%d{yyyy-MM-dd:HH:mm:ss.SSS} %r [%thread] %-5level %c %M %L  %msg%n"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 字符串System.out(默认)或者System.err -->
        <target>System.out</target>
        <!-- 对记录事件进行格式化 -->
        <encoder>
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>
    <!-- 输出日志到文件 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <!-- 设置日志输出格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- 设置日志保存位置 -->
        <file>logs/logback/test.log</file>
    </appender>
    <!-- 输出到文件 日志动态滚动 通过时间 和大小 -->
    <appender name="RFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建 -->
        <file>logs/RFILE.log</file>
        <!-- 当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 必要节点,包含文件名及"%d"转换符,"%d"可以包含一个java.text.SimpleDateFormat指定的时间格式,默认格式是 yyyy-MM-dd -->
            <fileNamePattern>logs/logback/%d{yyyyMMddHHmm}/log_%d{yyyyMMddHHmm}_%i.log</fileNamePattern>
            <!-- 通过日志大小来滚动日志 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10KB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,如果是6,则只保存最近6个月的文件,删除之前的旧文件 -->
            <maxHistory>5</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- LevelFilter: 级别过滤器,根据日志级别进行过滤  可选-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <!-- 用于配置符合过滤条件的操作 ACCEPT:日志会被立即处理,不再经过剩余过滤器 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 DENY:日志将立即被抛弃不再经过其他过滤器 -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <root level="TRACE">
        <appender-ref ref="console"/>
        <appender-ref ref="FILE"/>
        <appender-ref ref="RFILE"/>
    </root>
</configuration>
根据时间+大小滚动
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!-- 设置格式化输出格式 -->
    <property name="pattern" value="%d{yyyy-MM-dd:HH:mm:ss.SSS} %r [%thread] %-5level %c %M %L  %msg%n"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 字符串System.out(默认)或者System.err -->
        <target>System.out</target>
        <!-- 对记录事件进行格式化 -->
        <encoder>
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>
    <!-- 输出日志到文件 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <!-- 设置日志输出格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- 设置日志保存位置 -->
        <file>logs/logback/test.log</file>
    </appender>


    <!-- 输出到文件 日志动态滚动 通过时间 和大小 -->
    <appender name="RFILE2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建 -->
        <file>logs/RFILE2.log</file>
        <!-- 当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 必要节点,包含文件名及"%d"转换符,"%d"可以包含一个java.text.SimpleDateFormat指定的时间格式,默认格式是 yyyy-MM-dd -->
            <fileNamePattern>logs/logback/%d{yyyyMMddHHmm}/log_%d{yyyyMMddHHmm}_%i.log</fileNamePattern>
            <!-- 通过日志大小来滚动日志 -->
            <maxFileSize>10KB</maxFileSize>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,如果是6,则只保存最近6个月的文件,删除之前的旧文件 -->
            <maxHistory>5</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- LevelFilter: 级别过滤器,根据日志级别进行过滤 可选-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <!-- 用于配置符合过滤条件的操作 ACCEPT:日志会被立即处理,不再经过剩余过滤器 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 DENY:日志将立即被抛弃不再经过其他过滤器 -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <root level="TRACE">
        <appender-ref ref="console"/>
        <appender-ref ref="FILE"/>
        <appender-ref ref="RFILE2"/>
    </root>
</configuration>

完整配置

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!--
    | 占位符               | 作用                                                         |
    | %c = %log = %logger  | 输出日志的logger名                                           |
    | %c = %class          | 输出执行记录请求的调用者的全限定名                           |
    | %contextName = %cn   | 输出上下文名称                                               |
    | %d = %date           | 输出日志的打印日志                                           |
    | %F = %file           | 输出执行记录请求的java源文件名                               |
    | %caller              | 输出生成日志的调用者的位置信息,整数选项表示输出信息深度     |
    | %L = %line           | 输出执行日志请求的行号                                       |
    | %m = %msg = %message | 输出应用程序提供的信息                                       |
    | %M = %method         | 输出执行日志请求的方法名                                     |
    | %n                   | 输出平台先关的分行符                                         |
    | %p = %le = %level    | 输出日志级别                                                 |
    | %r = %relative       | 输出从程序启动到创建日志记录的时间,单位毫秒                 |
    | %t = %thread         | 输出产生日志的线程名                                         |
    | %replace(p){r,t}     | 替换内容 p 为日志内容,r 是正则表达式,将p 中符合r 的内容替换为t |
-->
    <!-- 设置格式化输出格式 -->
    <property name="pattern" value="%d{yyyy-MM-dd:HH:mm:ss.SSS} %r [%thread] %-5level %c %M %L  %msg%n"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 字符串System.out(默认)或者System.err -->
        <target>System.out</target>
        <!-- 对记录事件进行格式化 -->
        <encoder>
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>
    <!-- 输出日志到文件 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <!-- 设置日志输出格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- 设置日志保存位置 -->
        <file>logs/logback/test.log</file>
    </appender>

    <!-- 输出到文件 日志动态滚动 通过时间 和大小 -->
    <appender name="RFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建 -->
        <file>logs/RFILE2.log</file>
        <!-- 当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 必要节点,包含文件名及"%d"转换符,"%d"可以包含一个java.text.SimpleDateFormat指定的时间格式,默认格式是 yyyy-MM-dd -->
            <fileNamePattern>logs/logback/%d{yyyyMMddHHmm}/log_%d{yyyyMMddHHmm}_%i.log</fileNamePattern>
            <!-- 通过日志大小来滚动日志 -->
            <maxFileSize>10KB</maxFileSize>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,如果是6,则只保存最近6个月的文件,删除之前的旧文件 -->
            <!--<maxHistory>5</maxHistory>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- LevelFilter: 级别过滤器,根据日志级别进行过滤 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <!-- 用于配置符合过滤条件的操作 ACCEPT:日志会被立即处理,不再经过剩余过滤器 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 DENY:日志将立即被抛弃不再经过其他过滤器 -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <root level="TRACE">
        <appender-ref ref="console"/>
        <appender-ref ref="FILE"/>
        <appender-ref ref="RFILE"/>
    </root>
</configuration>

日志门面

作用:所有的Java日志实现提供一个统一的接口,使项目与日志实现工具解耦

common-logging

依赖

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

<!-- 如果需要接入到 log4j 需要导入依赖 -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

<!-- 如果需要接入到 log4j2 需要导入依赖 -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jcl -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-jcl</artifactId>
    <version>2.17.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>

配置文件

创建文件:commons-logging.properties

# 使用commons-logging的SimpleLog
# org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
# 选择使用 log4j 或者 log4j2
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
# 选择jdk的 logger
#org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger

调用日志门面

package cn.chenzhen.logging;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MainLoggngApplication {
    private static final Log logger = LogFactory.getLog(MainLoggngApplication.class);
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            logger.trace("输出日志: trace " + i);
            logger.debug("输出日志: debug " + i);
            logger.info("输出日志: info " + i);
            logger.warn("输出日志: warn " + i);
            logger.error("输出日志: error " + i);
        }
    }
}

日志实现类查找原理

  1. 在classpath下寻找自己的配置文件commons-logging.properties
    如果找到,则使用其中定义的Log实现类
    org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog; //使用commons-logging的SimpleLog
    org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger;//选择使用 log4j
    org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger; //选择jdk的 logger
  2. 找不到commons-logging.properties文件,则在查找是否已定义系统环境变量
    org.apache.commons.logging.Log,找到则使用其定义的Log实现类
  3. 查看classpath中是否有Log4j的包,如果发现,则自动使用Log4j作为日志实现类。
  4. 使用JDK自身的日志实现类(JDK1.4以后才有日志实现类)
  5. 如果都没命中使用commons-logging自己提供的一个简单的日志实现类SimpleLog

SLF4J

依赖

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>

日志转换 依赖

slf4j-api.jar       	slf4j 的api接口jar包  
slf4j-ext.jar       	扩展功能  

吧日志转换到slf4j
	jcl-over-slf4j.jar    	将Jakarta Commons Logging(commons-logging)日志框架到 slf4j 的桥接  
	jul-to-slf4j.jar      	将java.util.logging的日志桥接到 slf4j  
	log4j-over-slf4j.jar  	将log4j 的日志,桥接到slf4j  
	log4j-to-slf4j.jar		将log4j2 的日志 桥接到slf4j log4j2官方提供的jar
	osgi-over-slf4j.jar   	将osgi环境下的日志,桥接到slf4j  
	slf4j-android.jar     	将android环境下的日志,桥接到slf4j
	
slf4j吧日志输出到指定日志
	slf4j-jcl.jar      		slf4j 转接到 Jakarta Commons Logging日志输出框架  
	slf4j-jdk14.jar    		slf4j 转接到 java.util.logging,所以这个包不能和jul-to-slf4j.jar同时用,否则会死循环!!  
	slf4j-log4j12.jar  		slf4j 转接到 log4j,所以这个包不能和log4j-over-slf4j.jar同时用,否则会死循环!!  
	slf4j-migrator.jar 		一个GUI工具,支持将项目代码中 JCL,log4j,java.util.logging的日志API转换为slf4j的写法  
	slf4j-nop.jar      		slf4j的空接口输出绑定,丢弃所有日志输出  
	slf4j-simple.jar   		slf4j的自带的简单日志输出接口  
	log4j-slf4j-impl		输出到log4j2 有apache提供

日志框架替换

jcl 替换
<!-- 转接到 SLF4J -->
<!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.36</version>
</dependency>
log4j2 替换
<!-- 吧 log4j2 日志转接到 SLF4J -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-to-slf4j -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-to-slf4j</artifactId>
    <version>2.17.2</version>
</dependency>
log4j替换
<!-- 吧log4j日志转接到 SLF4J -->
<!-- https://mvnrepository.com/artifact/org.slf4j/log4j-over-slf4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.36</version>
</dependency>

日志实现

吧日志输出到 jcl
<!-- 吧日志输出到 commons-logging  -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jcl -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jcl</artifactId>
    <version>1.7.36</version>
</dependency>
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
吧日志输出到 JDK日志
<!-- 吧日志输出到 JDK自带日志  -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.36</version>
</dependency>
吧日志输出到log4j
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.36</version>
    <type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
吧日志输出到 log4j2
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.17.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>
吧日志输出到 logback
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值