12- JavaLogs

2021-03-02  本文已影响0人  XAbo

日志门面:类似与JDBC,使用一套接口,操作不同实现。

日志图谱

日志框架出现的顺序:log4j>>jul>>jcl>>slf4j>>logback>>log4j2
log4j2:即使日志门面也是日志实现

一、JUL

全称Java Util Logging 是JAVA原生的日志框架,使用时不需要引用三方Jar类库。

1.1 JUL入门

public class JULTest {
    public void test01() {
        Logger logger = Logger.getLogger("com.examples.logs");
        logger.info("你好");
        logger.warning("警告!!!!");
       //通用的日志方法
        logger.log(Level.INFO,"HELLO WORLD !!");
        String name ="z";
        String age = "0";
        //使用占位符的通用方法
        logger.log(Level.INFO,"{0},{1}",new Object[]{name,age});
        
        //日志级别
        //logger.setLevel(Level.ALL); 
        //logger.setLevel(Level.OFF);
        logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        logger.severe("severe");
        logger.warning("warning");
        //默认级别
        logger.info("info");
        logger.config("config");
        logger.fine("fine");
        logger.finer("finer");
        logger.finest("finest");
    }
    public static void main(String[] args) throws  Exception {
        JULTest jul = new JULTest();
        jul.test01();

    }
}

1.2 自定义日志

import java.util.logging.*;

public class JULTest {
    public void test02() throws Exception{
        SimpleFormatter simpleFormatter = new SimpleFormatter();
        Logger logger = Logger.getLogger("com.examples.logs");//儿子
        Logger logger1 = Logger.getLogger("com.examples");//爸爸
        Logger logger0 = logger1.getParent();//爷爷  无名氏
        System.out.println(logger1==logger.getParent());
        System.out.println(logger0+"--->"+logger0.getName());

        // 0. 爷爷的默认
        // 默认INFO,需要使用consoleHandler0修改默认级别才能输出全部级别日志
        ConsoleHandler consoleHandler0 = new ConsoleHandler();
        logger0.addHandler(consoleHandler0);
        consoleHandler0.setLevel(Level.ALL);
        logger0.setLevel(Level.ALL);
        logger0.severe("爷爷的severe");
        logger0.warning("爷爷的warning");
        logger0.info("爷爷的info");
        logger0.config("爷爷的config");
        logger0.fine("爷爷的fine");
        logger0.finer("爷爷的finer");
        logger0.finest("爷爷的finest");

        // 1.爸爸在控制台:输出所有日志,使用自定义的日志级别
        // 爸爸关闭爷爷日志级别配置
        logger1.setUseParentHandlers(false);
        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(simpleFormatter);
        logger1.addHandler(consoleHandler);
        consoleHandler.setLevel(Level.WARNING);
        logger1.setLevel(Level.ALL);
        logger1.severe("爸爸的severe");
        logger1.warning("爸爸的warning");
        logger1.info("爸爸的info");
        logger1.config("爸爸的config");
        logger1.fine("爸爸的fine");
        logger1.finer("爸爸的finer");
        logger1.finest("爸爸的finest");

        // 2.儿子在文件中输出日志:输出错误日志,使用自定义的日志级别
        logger.setUseParentHandlers(false);
        FileHandler fileHandler = new FileHandler("C:\\Users\\Administrator\\Desktop\\logs.txt");
        fileHandler.setFormatter(simpleFormatter);
        logger.addHandler(fileHandler);
        fileHandler.setLevel(Level.SEVERE);
        logger.setLevel(Level.ALL);
        logger.severe("severe");
        logger.warning("warning");
        logger.info("info");
        logger.config("config");
        logger.fine("fine");
        logger.finer("finer");
        logger.finest("finest");
    }
    public static void main(String[] args) throws  Exception {
        JULTest jul = new JULTest();
        jul.test02();
    }
}

结果:

控制台 文件

1.3 使用配置文件

JDK默认的日志文件在

 $JAVA_HOME/jre/lib

实例:

#指定顶级父元素RootLogger默认处理器
handlers= java.util.logging.ConsoleHandler
.level= ALL

java.util.logging.FileHandler.pattern = %h/java%u.log

java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter


#自定义Logger
com.simple.handlers =  java.util.logging.ConsoleHandler
com.simple.level=ALL
#关闭RootLogger配置
com.simple.ueParentHandlers = false

客户端:

package com.examples.logs;
import java.io.InputStream;
import java.util.logging.*;
public class JULTest {
    public void test02() throws Exception{
        InputStream ins = JULTest.class.getClassLoader().getResourceAsStream("logging.properties");
        LogManager logManager = LogManager.getLogManager();
        logManager.readConfiguration(ins);
        Logger logger1 = Logger.getLogger("com.examples");//爸爸
        Logger logger0 = logger1.getParent();//爷爷  无名氏
        logger0.severe("爷爷的severe");
        logger0.warning("爷爷的warning");
        logger0.info("爷爷的info");
        logger0.config("爷爷的config");
        logger0.fine("爷爷的fine");
        logger0.finer("爷爷的finer");
        logger0.finest("爷爷的finest");

    }
    public static void main(String[] args) throws  Exception {
        JULTest jul = new JULTest();
        jul.test02();
    }
}
结果

二、Log4J

是Apache的一款开源日志框架,通过在项目中使用log4j,我们可以控制日志信息输出到控制台、文件甚至是数据库中。

Log4j主要有Loggers(日志记录器,是category的别名)、Appenders(输出端)和Layout(日志格式化器)组成。其中Loggers控制日志的输出级别与日志是否输出;Appenders指定日志的输出方式;控制日志的输出格式。

自定义日志使用场景:第三方日志。

Loggers

Loggers层级
Appenders

Layout

2.1 入门案例

pom.xml

   <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.17</version>
   </dependency>

客户端:

package com.examples.logs;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
public class Log4jTest {

   public void test1() throws  Exception{
       //不适应配置文件进行初始化
       BasicConfigurator.configure();
       //获取日志记录
       Logger logger = Logger.getLogger(Log4jTest.class);
       //默认日志级别是debug
       logger.fatal("fatal");//验证错误,一般会造成系统崩溃并终止运行
       logger.error("error");//错误信息,不会影响系统运行
       logger.warn("warn");//警告信息,可能会发生的问题
       logger.info("info");//运行信息
       logger.debug("debug");//调试信息
       logger.trace("trace");//追踪信息,记录程序所有流程信息
    }
    public static void main(String[] args) throws  Exception{
        Log4jTest log4jTest = new Log4jTest();
            log4jTest.test1();
    }
}
结果

2.2 使用配置文件

log4j.properties

log4j.rootLogger=info,console,fileAppender,rollingFile 
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

log4j.appender.fileAppender = org.apache.log4j.FileAppender
log4j.appender.fileAppender.File = D:/xzv.log
log4j.appender.fileAppender.Append = true
log4j.appender.fileAppender.Threshold = DEBUG
log4j.appender.fileAppender.layout = org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m\n

log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.Threshold=ERROR
log4j.appender.rollingFile.File=D:/xzb.log
log4j.appender.rollingFile.MaxFileSize=10KB
log4j.appender.rollingFile.Append = true
log4j.appender.rollingFile.MaxBackupIndex=10
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss.SSS}  [ %t:%r ] - [ %p ]  %m\n
# 配置文件中layout的pattern的格式:
# %m:输出代码中指定的日志信息。
# %p:输出优先级及DEBUG、INFO等。
# %n:换行符Windows:"\n";Unix:"%n"。
# %r:输出自应用启动到输出该LOG信息耗费的毫秒数
# %c:输出打印语句所属的类的全名。
# %t:输出产生该日志的线程全名。
# %d:输出服务器当前时间,默认ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss}。
# %l:输出日志时间发生的位置,包括类名、线程和代码中的行数。
# %F:输出日志消息产生时所在的文件名称。
# %L:输出代码中的行号
# %%输出一个“%”字符。

# %5c:输出category名称,最小宽度是5,category<5,默认的情况下右对齐。
# %-5c:输出category名称,最小宽度是5,“-”号指定左对齐,会有空格。
# .5c:输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格。
# %20.30c category名称<20补空格,并且右对齐,>30字符,就从左边将多出的字符截掉。

Log4jTest.java

public class Log4jTest {

   public void test1() throws  Exception{
       //开启LOG4J内置日志
       LogLog.setInternalDebugging(false);
       Logger logger = Logger.getLogger(Log4jTest.class);
        for (int i = 0; i < 100; i++) {
            logger.fatal("fatal");//验证错误,一般会造成系统崩溃并终止运行
            logger.error("error");//错误信息,不会影响系统运行
            logger.warn("warn");//警告信息,可能会发生的问题
            logger.info("info");//运行信息
            logger.debug("debug");//调试信息
            logger.trace("trace");//追踪信息,记录程序所有流程信息
        }
    }
    public static void main(String[] args) throws  Exception{
        Log4jTest log4jTest = new Log4jTest();
        log4jTest.test1();
    }
}

结果:

结果

三、 JCL日志门面

当项目从JUL转变为Log4J的时候,由于接口不同,代价是巨大的。JCL就是为解决此问题的,所有日志的实现将提供统一的接口,改变日志的实现而不需要更改程序。


JCL
JCL原理

日志门面支持的日志实现数组

private static final String[] classesToDiscover = {
    "org.apache.commons.logging.impl.Log4JLogger",
    "org.apache.commons.logging.impl.Jdk14Logger",
    "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
    "org.apache.commons.logging.impl.SimpleLog"
}

获取具体的日志实现:

for(int i = 0; i < classesToDiscover.length && result == null; ++i)
 {
        result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
}

3.1 入门案例

客户端:

package com.examples.logs;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JCLTest {
    public void test1() {
        Log log = LogFactory.getLog(JCLTest.class);
        log.info("大家好!!!");
    }
    public static void main(String[] args) {
        JCLTest  jcl  = new JCLTest();
        jcl.test1();
    }
}

3.1.1 只引入commons-logging包

    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
只引入commons-logging

3.1.2 引入log4j不引入配置文件

 <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
   <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.17</version>
   </dependency>
引入log4j不引入配置文件

3.1.3 引入log4j和配置文件

引入log4j和配置文件

四、SLF4J日志门面

原理:

客户端:

package examples.logs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4JTest {
    public static  final Logger LOGGER = LoggerFactory.getLogger(SLF4JTest.class);
    public void test1() {
        LOGGER.error("错误");
        LOGGER.warn("警告");
        LOGGER.info("信息");
        LOGGER.debug("BUG");
        //使用占位符
        String name ="xzv";
        int age = 30;
        LOGGER.info("name:{},{}",name,age);
        //将系统异常信息输出
        try {
            int i =1/0;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.warn("警告",e);
        }
    }
    public static void main(String[] args) {
        SLF4JTest jcl  = new SLF4JTest();
        jcl.test1();
    }
}

4.1 入门案例

pom.xml: 自带的日志实现

 <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.21</version>
        </dependency>
    </dependencies>
自带的日志实现

4.2 日志绑定

image.png
 - 添加slf4j-api的依赖。
 - 使用slf4j的API在项目中进行统一的日志记录。
 - 绑定具体的日志实现框架
   - 1 绑定已经实现了slf4j的日志框架,直接添加对应的依赖。
   - 2 绑定没有实现slf4j的日志框架,先添加日志的适配器,再添加实现类的依赖
- slf4j有且仅有一个日志实现框架的绑定。(如果出现多个默认使用第一个依赖日志实现)

4.2.1 绑定logback

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
绑定logback

4.2.2 绑定nop

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.25</version>
        </dependency>
    </dependencies>

结果:没有输出日志框架的日志。

绑定nop

4.2.3 绑定 log4j

pom.xml

     <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
       <!--绑定log4j 日志实现,导入适配器-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
绑定 log4j-未引入配置文件
绑定 log4j-引入配置文件

4.2.4 绑定 JUL

pom.xml

       <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
       <!--绑定JUL日志实现,导入适配器,JUL是JDK内置的,不需要添加实现-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
           <version>1.7.31</version>
        </dependency>
绑定 JUL

4.2.5 slf4j桥接器

应用场景:当旧项目的日志框架log4j需要更换为slf4j+logback的时候,又不想修改源代码。使用桥接可以处理
原项目的pom.xml

   <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.17</version>
   </dependency>

新项目的pom.xml

        <!---1. 先导入日志门面--->
       <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
       <!---2. 导入需要更换的logback;仅仅导入logback源代码是会报错的--->
       <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
      <!---3. 导入桥接器--->
       <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
            <version>1.7.25</version>
        </dependency>

桥接器注意事项:
1.jcl-over-slf4j.jar和slf4j-jcl.jar不能同时部署。
2.log4j-over-slf4j.jar和slf4j-log4j12.jar不能同时出现。
3.jul-to-slf4j.jar和slf4j-jdk14.jar不能同时出现。


log4j-over-slf4j.jar和slf4j-log4j12.jar

五、Logback

Logback是由log4j创始人设计的另一个开源日志组件。
Logback主要分为三个模块:

5.1 logback入门

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Theme</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>Logback</artifactId>
    <dependencies>
       <!--   maven传递依赖,不需要导入slf4j-api
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
       -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
</project>

客户端:

package com.theme.logback;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
public class LogbackTest {
    public static final Logger LOGGER = LoggerFactory.getLogger(LogbackTest.class);
    public void test1() {
        LOGGER.error("错误");
        LOGGER.warn("警告");
        LOGGER.info("信息");
        LOGGER.debug("BUG");
    }
    public static void main(String[] args) {
        LogbackTest logbackTest = new LogbackTest();
        logbackTest.test1();
    }
}

结果:

image.png

5.2. logback配置

logback会依次读取以下类型的配置文件logback.groovylogback-test.xmllogback.xml 如果均不存在会采用默认配置。

logback组件之间的关系:
Logger:日志的记录器,把它关联到应用对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。
Appender:用于指定日志输出的目的地。
Layout:负责把事件转换成字符串,格式化的日志信息的输出。在logback对象被封装在encoder中。

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
    <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/logggs"/>

    <!--控制台日志, 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!--控制输出对象 默认System.out 修改为System.err-->
        <target>System.err</target>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <!--日志文件-->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/logback.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <!--HTML日志文件-->
    <appender name="HTMLFILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/logback.html</file>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
            <pattern>${pattern}</pattern>
            </layout>
        </encoder>
    </appender>


    <!--日志文件 拆分-->
    <appender name="ROLLFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/roll_logback.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
         <!--按照时间和压缩格式声明拆分的文件名-->
        <fileNamePattern>${LOG_HOME}/roll.%d{yyyy-MM-dd HH:mm:ss.SSS}log%i.gz</fileNamePattern>
          <!--按照文件大小拆分-->
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>

        <!--日志级别过滤器-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--日志过滤级别-->
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMisMatch>DENY</onMisMatch>
        </filter>
    </appender>
    <!--异步日志-->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
     <!--指定某个具体的appender-->
        <appender-ref ref="ROLLFILE"/>
    </appender>


    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
        <appender-ref ref="HTMLFILE"/>
        <appender-ref ref="ASYNC"/>
    </root>

    <!--自定义日志:表示com.theme.logback包下的日志走自定义的配置-->
    <logger name="com.theme.logback" level="info" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>
</configuration>

5.3.logback-access

logback-access模块与Servlet容器集成,以提供HTTP访问日志的功能。我们可以使用logback-access模块来替代tomcat的访问日志。

<value className="ch.qos.logback.access.tomcat.LogbackValue"/>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<statusLister class="ch.qos.logback.core.status.OnConsolesListener"/>
<property name="LOG_DIR" value="${catalina.base}/logs/">
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/access.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>${LOG_HOME}/roll.%d{yyyy-MM-dd HH:mm:ss.SSS}log%i.gz</fileNamePattern>
        <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
        <encoder>
            <pattern>combined</pattern>
        </encoder>
    </appender>
<appender-ref ref="FILE">
</configuration>

六、Log4j2

Log4j2是对Log4j的升级,参考了logback的优点;

6.1 Log4j2入门

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
    <dependencies>

       <!--第一种门面-->
       <!--log4j2日志门面-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.12.1</version>
        </dependency>
 
       <!--第二种门面-->
        <!--slf4j日志门面-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <!--使用log4j2适配器-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.9.1</version>
        </dependency>


        <!--log4j2日志实现 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.12.1</version>
        </dependency>
    </dependencies>

客户端:

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

public class Log4j2Test {
    public static final Logger LOGGER = LogManager.getLogger(Log4j2Test.class);
    public void test1() {
        LOGGER.fatal("fatal");
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.debug("debug");
        LOGGER.trace("trace");
    }

    public static void main(String[] args) {
        Log4j2Test logbackTest = new Log4j2Test();
        logbackTest.test1();
    }
}

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>

<!--
status:日志框架本身日志的级别
monitorInterval:自动加载配置文件的间隔时间,不低于5S
-->
<configuration status="OFF" monitorInterval="5">

    <properties>
        <property name="LOG_HOME">/logs</property>
    </properties>


    <appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <!--只接受程序中DEBUG级别的日志进行处理-->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{HH:mm:ss.SSS}] %-5level %class{36} %L %M - %msg%xEx%n"/>
        </Console>

        <file name="File" fileName="${LOG_HOME}/mylog.log">
            <PatternLayout pattern="[%d{HH:mm:ss.SSS}] %-5level %class{36} %L %M - %msg%xEx%n"/>
        </file>

        <!--随机读写流-->
        <RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAccessFile.log">
            <PatternLayout pattern="[%d{HH:mm:ss.SSS}] %-5level %class{36} %L %M - %msg%xEx%n"/>
        </RandomAccessFile>


        <!--处理INFO级别的日志,并把该日志放到logs/info.log文件中-->
        <RollingFile name="RollingFileInfo" fileName="${LOG_HOME}/logs/info.log"
                     filePattern="logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--只接受INFO级别的日志,其余的全部拒绝处理-->
                <ThresholdFilter level="INFO"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy/>
                <OnStartupTriggeringPolicy/>
            </Policies>
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>

        <!--druid的日志记录追加器-->
        <RollingFile name="druidSqlRollingFile" fileName="./logs/druid-sql.log"
                     filePattern="logs/$${date:yyyy-MM}/api-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
    </appenders>
    <!--     然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
    <loggers>
        <!--默认的root的logger-->
        <root level="DEBUG">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
        </root>
        <!--额外配置的logger-->
        <!--记录druid-sql的记录-->
        <logger name="druid.sql.Statement" level="debug" additivity="false">
            <appender-ref ref="druidSqlRollingFile"/>
        </logger>
        <!--log4j2 自带过滤日志-->
        <Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
        <Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
        <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
        <logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
        <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
        <Logger name="org.crsh.plugin" level="warn" />
        <logger name="org.crsh.ssh" level="warn"/>
        <Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
        <Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
        <logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
        <logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
        <logger name="org.thymeleaf" level="warn"/>
    </loggers>
</configuration>

6.2 Log4j2异步日志

摘自:https://blog.csdn.net/jek123456/article/details/100123570
pom.xml

<dependency>
     <groupId>com.lmax</groupId>
     <artifactId>disruptor</artifactId>
     <version>3.4.3</version>
 </dependency>

6.2.1 AsyncAppender方式

AsyncAppender是通过引用别的Appender来实现的,当有日志事件到达时,会开启另外一个线程来处理它们。需要注意的是,如果在Appender的时候出现异常,对应用来说是无法感知的。 AsyncAppender应该在它引用的Appender之后配置,默认使用 java.util.concurrent.ArrayBlockingQueue实现而不需要其它外部的类库。 当使用此Appender的时候,在多线程的环境下需要注意,阻塞队列容易受到锁争用的影响,这可能会对性能产生影响。这时候,我们应该考虑使用无所的异步记录器(AsyncLogger)。

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
 <Appenders>
   <File name="MyFile" fileName="logs/app.log">
     <PatternLayout>
       <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
     </PatternLayout>
   </File>
   <Async name="Async">
     <AppenderRef ref="MyFile"/>
   </Async>
 </Appenders>
 <Loggers>
   <Root level="error">
     <AppenderRef ref="Async"/>
   </Root>
 </Loggers>
</Configuration>

6.2.2 AsyncLogger方式

AsyncLogger才是log4j2 的重头戏,也是官方推荐的异步方式。它可以使得调用Logger.log返回的更快。
你可以有两种选择:全局异步和混合异步。

全局异步
不修改配置文件,在系统初始化的时候,增加全局参数配置:

System.setProperty("log4j2.contextSelector, "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");

你可以在你第一次获取Logger之前设置,也可以加载JVM启动参数里,类似

java -Dog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

混合异步

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
    <RandomAccessFile name="RandomAccessFile" fileName="asyncWithLocation.log"
              immediateFlush="false" append="false">
      <PatternLayout>
        <Pattern>%d %p %class{1.} [%t] %location %m %ex%n</Pattern>
      </PatternLayout>
    </RandomAccessFile>
  </Appenders>
  <Loggers>
    <!-- pattern layout actually uses location, so we need to include it -->
    <AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true">
      <AppenderRef ref="RandomAccessFile"/>
    </AsyncLogger>
    <Root level="info" includeLocation="true">
      <AppenderRef ref="RandomAccessFile"/>
    </Root>
  </Loggers>
</Configuration>

在使用异步日志的时候需要注意一些事项,如下:

上一篇下一篇

猜你喜欢

热点阅读