Java的Log架构(Log4j2 + Slf4j)

目录

常见的日志门面

常见的日志实现

日志框架介绍

JUL

Log4j

LogBack

Log4j2

SLF4J的使用

简介

slf4j-api 和 slf4j-simple 使用

Log4j2的使用

简介

Demo

异步日志(效率提升的原因)

使用Log4j2和slf4j的日志架构

包引入

Domo实现

Log4j2的配置文件

Log4j2配置异步日志

Log4j2无垃圾机制


常见的日志门面

JCL,slf4j(Simple Logging For java)

 

常见的日志实现

JUL,log4j,logback,log4j2

 

日志框架介绍

JUL

Java自带的日志框架,不需要引入,直接可以使用

Log4j

非常经典的日志框架,但是已经停止更新和维护了

LogBack

logBack和log4j不是同一个公司开发的,LogBack是Spring自动集成的日志框架了。目前比较流行

Log4j2

Log4j2是Log4j的进阶版,相比于LogBack,在异步的时候速度可以快近10倍,目前Spring项目中,都会把自动引入的LogBack注释掉,改用Log4j2. 未来使用Log4j2+slf4j这套组合一定是未来的几年的主流日志框架。

 

SLF4J的使用

简介

SLF4J(Simple Logging Facade For Java)是给Java日志访问提供的一套标准,具体的实现,主要交给log4j,logback,log4j2等日志框架。SLF4J其实也实现了简单的日志实现,但是几乎不会有人去使用,而日志框架一般会选择slf4j-api作为门面,配上具体的实现框架,中间使用连接桥(适配器)来完成日志框架的建立。 slf4j-api 和 slf4j-simple 引入。 api是日志门户,simple是日志的简单实现。

slf4j-api 和 slf4j-simple 使用

log的级别有trace,debug,info,warn,error和fatal六个级别,默认情况下,只会输出info,warn和error,fatal四个级别的日志。 占位符的使用,可以使用{}作为占位符,后边跟具体的变量,只要能使用占位符就一定要使用这种模式作为日志模式,但是需要小心注入攻击。 使用slf4j-api 和 slf4j-simple的方式输出日志,不需要导入中间的适配器,当多个log实现框架同时存在的时候,会默认先使用slf4j-simple框架。

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
public class Slf4jTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);
​
    @Test
    public void test01() {
        // 日志输出,默认会输出info级别以上的日志
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info");
        LOGGER.debug("debug");
        LOGGER.trace("trace");
​
        // 使用占位符输出日志信息
        String name = "Peter";
        Integer age = 10;
        LOGGER.info("User:{}, Age:{}", name, age);
    }
​
}

 

Log4j2的使用

简介

        Apache Log4j2 是 log4j 的升级版,参考了logback的优秀设计,优化并解决了很多问题: 异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中提供了一些异常处理机制。 性能提升,log4j2相比于logback和log4j在性能上有了很大的提升。 自动重载配置,提供了自动刷新参数配置,可以再生产上动态修改日志的级别而不需要重启应用。 无垃圾机制,log4j2在大部分情况下,使用自动垃圾清收机制,避免日志频繁的GC。 Log4j2 也可以做为日志的门面,但是因为其实现功能强大,但是门面略弱,所以当前主流的日志框架都是使用slf4j作为日志的门面,使用Log4j2作为日志的实现,通过连接器绑定,进行工作。 使用log4j-api和log4j-core的日志架构如下:

依赖信息:
<!--导入日志门面-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.13.3</version>
</dependency>
​
<!--导入日志实现-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.3</version>
</dependency>

Demo

package logger;
​
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;
​
public class Log4j_Api_Core {
    private static final Logger LOGGER = LogManager.getLogger(Log4j_Api_Core.class);
​
    @Test
    public void test02(){
        // 日志输出,默认会输出info级别以上的日志
        LOGGER.fatal("fatal");
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info");
        LOGGER.debug("debug");
        LOGGER.trace("trace");
​
        // 使用占位符输出日志信息
        String name = "Peter";
        Integer age = 10;
        LOGGER.info("User:{}, Age:{}", name, age);
    }
​
}

异步日志(效率提升的原因)

同步日志:

正常的日志,在线程需要打印日志的时候,会走一套流程,初始化,并生成日志,判断等级是否过滤等等,最后决定是否输出异步日志:

异步日志

异步日志的使用方式是在主线程需要生成日志之后,就将信息传递给一个阻塞的消息队列ArrayBlockingQueue,这个队列将启动一个(或多个)新的线程,完成后续日志的生成,所以效率高了很多

性能图表:

通常使用全局异步日志的效率最高,使用异步日志和同步日志混合的效率其次,使用同步日志的效率最低。通常情况下,都会直接使用异步日志提高效率。

 

使用Log4j2和slf4j的日志架构

当前最主流的日志使用方式事Log4j2作为实现,slf4j作为门户。

包引入

这个组合需要引入4个包,分别为Log4j2的门户和实现,slf4j的门户,slf4j和Log4j2的连接器。 之后就可以按照slf4j的所有实现模式和门户模式进行操作了。

<!--导入slf4j日志门面-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>
​
<!--导入log4j2日志实现-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.3</version>
</dependency>
<!--导入log4j2日志门面-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.13.3</version>
</dependency>
​
<!--使用适配器-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.9.1</version>
</dependency>

Domo实现

使用slf4j和log4j2的组合,Demo如下:

package logger;
​
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
public class Slf4j_Log4j2 {
    private static final Logger LOGGER = LoggerFactory.getLogger(Slf4j_Log4j2.class);
​
    @Test
    public void test03() {
        // 日志输出,默认会输出info级别以上的日志
        LOGGER.error("error");
        LOGGER.warn("warn");
        LOGGER.info("info");
        LOGGER.debug("debug");
        LOGGER.trace("trace");
​
        // 使用占位符输出日志信息
        String name = "Peter";
        Integer age = 10;
        LOGGER.info("User:{}, Age:{}", name, age);
    }
​
}

Log4j2的配置文件

log4j2 默认会加载在resources下的xml配置文件,名称为log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
​
<!--status = debug 日志框架本身的输出的日志级别,不是我们定义的日志,而是框架自身日志输出的级别-->
<!--monitorInterval 自动加载配置文件的间隔时间,不低于5s,可以实现热更新-->
<Configuration status="debug" monitorInterval="5">
    <!-- 集中配置属性进行管理  可以定义各种名称和对应的值 -->
    <properties>
        <property name="LOG_HOME">E:/logs</property>
        <property name="FILE_NAME">mylog</property>
        <property name="log.sql.level">info</property>
    </properties>
​
    <!--日志处理-->
    <Appenders>
        <!--控制台输出结果 appender-->
        <!--target 为日志的等级,如果为 SYSTEM_OUT 是普通日志,为白色;如果是SYSTEM_ERR,则为报警颜色,红色-->
        <Console name="Console" target="SYSTEM_OUT">
            <!--日志输出的格式-->
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>
        </Console>
​
        <!-- 日志的文件输出 -->
        <File name="file" fileName="${LOG_HOME}/myfile.log">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n"/>
        </File>
​
        <!--随机读写流实现文件日志的输出,性能得到了提高,功能和 name = file是一样的-->
        <RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n"/>
        </RandomAccessFile>
​
        <!--按照一定的规则拆分日志文件的(比如按照天,按照小时拆分日志) appender-->
        <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${LOG_HOME}/${FILE_NAME}.log"
                                 filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
            <!--日志级别的过滤器-->
            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n"/>
            <Policies>
                <!--在系统启动时,触发拆分规则,生产一个新的日志文件-->
                <OnStartupTriggeringPolicy/>
                <!--按照时间的节点进行拆分,规则根据filePattern定义-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <!--按照10Mb大小为一个文件的上限-->
                <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <!--最多可以生成多少个日志文件,超出之后,最旧的会被覆盖-->
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>
    </Appenders>
​
    <!--Logger定义-->
    <Loggers>
        <!--日志输出的等级,超过该等级的进行输出-->
        <Root level="info">
            <!--指定日志的处理器-->
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingRandomAccessFile"/>
            <AppenderRef ref="file"/>
            <AppenderRef ref="accessFile"/>
        </Root>
    </Loggers>
​
</Configuration>

Log4j2配置异步日志

异步配置有两种方式,全局异步和局部异步(异步和同步混合的方式)。局部异步的方式,如果处理不好,可能性能比完全同步效率还低,因此,仅介绍全局异步的使用方式。

需要引入一个新的jar包,用于异步日志生成;

<!--异步log4j2日志的依赖包-->
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.4</version>
</dependency>

之后在resources下,定义一个文件 log4j2.component.properties 在这个文件中启动全局异步日志的指令即可:

log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

Log4j2无垃圾机制

在log4j2的2.6版本之后,会启动一个无垃圾机制,它会自动的清除日志中的垃圾,减少了系统自动GC的频率,大大提高了速度(无垃圾机制自动开启,不需要手动操作)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值