手记

『互联网架构』软件架构-java日志体系(17)

了解过为什么日志体系那么多的jar包,系统放几天日志就把线上磁盘给打爆了。具体怎么配置使用log,有的配置是Info是一个日志,error是一个日志,查找非常的烦,如果线上不出问题,我们很少管,如果出问题了,找不到对应的日志真是烦透了。如果是分布式开发,日志管理如果不使用elk这种统一工具,分散在不同的机器上,有10台机器需要去10台机器轮流找日志,是不是很麻烦,今天就一次性的吧整个日志体系搞明白。

JAVA当中有哪些日志打印的组件

名称

描述

log4j

logback

log4j2

java.util.logging

  • 假设Spring 框架要打印日志,应该选择中其中哪一个组件?

发现哪个都不能选,只能基于应用实际使用的日志组件来。不然就会日志打印会多份。怎么找到应用实际使用的日志组件 Apache Commons Loging 解决了这个问题

  • Apache Commons Loging (JCL)

Commons Loging 本身只提供日志接口,具体实现在运行时动态寻找对应组件?比如:log4j、jdk14looger 等。但这种动态绑定的方式当系统特别宠大的时候会出现绑定失败的问题。现在比较流行的slf4j 基于静态绑定的方式解决了这个问题?

  • slf4j

sl4j 本身也只提供日志接口,与commons loging 不同的是其采用在classPath 加入以下jar包来表示具体采用哪种实现 :
• slfj-log4j12.jar (表示指定 log4j)
• slf4j-jdk14.jar(表示指定jdk Looging)
• slf4j-jcl.jar(表示指定jcl)
• log4j-slf4j-impl(表示指定log4j2)
• logback-classic(表示指定logback)

  • 门面模式

JCL 和slf4j 都使用了一种外观模式(门面模式)
外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。

简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中,设计到3个角色。

  1. 门面角色:外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合。

  2. 子系统角色:实现了子系统的功能。它对客户角色和Facade时未知的。它内部可以有系统内的相互交互,也可以由供外界调用的接口。

  3. 客户角色:通过调用Facede来完成要实现的功能。

日志的发展历史

最先出现的是apache开源社区的log4j,这个日志确实是应用最广泛的日志工具,成为了java日志的事实上的标准。然而,当时Sun公司在jdk1.4中增加了JUL日志实现,企图对抗log4j,但是却造成了混乱,这个也是被人诟病的一点。当然也有其他日志工具的出现,这样必然造成开发者的混乱,因为这些日志系统互相没有关联,替换和统一也就变成了比较棘手的一件事。想象下你的应用使用log4j,然后使用了一个其他团队的库,他们使用了JUL,你的应用就得使用两个日志系统了,然后又有第二个库出现了,使用了simplelog。这个时候估计让你崩溃了,这是要闹哪样?这个状况交给你来想想办法,你该如何解决呢?进行抽象,抽象出一个接口层,对每个日志实现都适配或者转接,这样这些提供给别人的库都直接使用抽象层即可。不错,开源社区提供了commons-logging抽象,被称为JCL,也就是日志框架了,确实出色地完成了兼容主流的日志实现(log4j、JUL、simplelog),基本一统江湖,就连顶顶大名的spring也是依赖了JCL。看起来事物确实是美好,但是美好的日子不长,接下来另一个优秀的日志框架slf4j的加入导致了更加混乱的场面。比较巧的是slf4j的作者(Ceki Gülcü)就是log4j的作者,他觉得JCL不够优秀,所以他要自己搞一套更优雅的出来,于是slf4j日志体系诞生了,并为slf4j实现了一个亲子——logback,确实更加优雅,但是由于之前很多代码库已经使用JCL,虽然出现slf4j和JCL之间的桥接转换,但是集成的时候问题依然多多,对很多新手来说确实会很懊恼,因为比单独的log4j时代“复杂”多了,可以关注下这个,抱怨声确实很多。到此本来应该完了,但是Ceki Gülcü觉得还是得回头拯救下自己的“大阿哥”——log4j,于是log4j2诞生了,同样log4j2也参与到了slf4j日志体系中,想必将来会更加混乱。

slf4j的设计确实比较优雅,采用比较熟悉的方式——接口和实现分离,有个纯粹的接口层——slf4j-api工程,这个里边基本完全定义了日志的接口,所以对于开发来说,只需要使用这个即可。有接口就要有实现,比较推崇的实现是logback,logback完全实现了slf4j-api的接口,并且性能也比log4j更好,同时实现了变参占位符日志输出方式等等新特性。刚刚也提到log4j的使用比较普遍,所以支持这批用户依然是必须的,slf4j-log4j12也实现了slf4j-api,这个算是对log4j的适配器。同样推理,也会有对JUL的适配器slf4j-jdk14等等。为了使使用JCL等等其他日志系统后者实现的用户可以很简单地切换到slf4j上来,给出了各种桥接工程,比如:jcl-over-slf4j会把对JCL的调用都桥接到slf4j上来,可以看出jcl-over-slf4j的api和JCL是相同的,所以这两个jar是不能共存的。jul-to-slf4j是把对jul的调用桥接到slf4j上,log4j-over-slf4j是把对log4j的调用桥接到slf4j。

log追加文件

log4j2的配置

  • HelloSlf4j
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloSlf4j {
    private static Logger logger = LoggerFactory.getLogger(HelloSlf4j.class);

    public static void main(String[] args) {
      /*  org.apache.log4j.Logger logger1=   org.apache.log4j.Logger.getLogger(HelloSlf4j.class);
        logger1.error("log4-error - abcd");
        logger1.info("log4- info -abcd");*/


        for (int i = 0; i < 2000; i++) {
            logger.error("slf4j- error - abcd");
            logger.info("slf4j- info -abcd");
        }
    }
}


  • log4j2.xml
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="error">
    <!-- 定义输出源 -->
    <Appenders>
        <Console name="Console" target="SYSTEM_ERR">
            <PatternLayout pattern="%d [%-5level][%t] %m (%C:%F:%L) %n"/>
        </Console>
        <!--  测试环境使用-->
        <File name="file" fileName="logs/all.log" append="false">
            <PatternLayout pattern="%d [%-5level][%t] %m (%C:%F:%L) %n"/>
        </File>
        <RollingFile name="rollingFile" fileName="logs/all-3.log"
                     filePattern="logs/$${date:yyyy-MM-dd}/all-%d{yyyy-MM-dd-HH}-%i.zip">
            <PatternLayout pattern="%d [%-5level][%t] %m (%C:%F:%L) %n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="2 KB"/>
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingFile>


        <RollingFile name="errorRollingFile" fileName="logs/error2.log"
                     filePattern="logs/$${date:yyyy-MM-dd}-error/error-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%d [%-5level][%t] %m (%C:%F:%L) %n"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="2 KB"/>
            </Policies>
            <DefaultRolloverStrategy max="5"/>
        </RollingFile>
    </Appenders>

    <!--  具体的日志配置 name =-->
    <Loggers>
        <AsyncRoot  level="debug">
            <AppenderRef ref="errorRollingFile"/>
        </AsyncRoot>
    </Loggers>
</Configuration>

  • 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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>tuling-logging</groupId>
    <artifactId>tuling</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--slf4j门面 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!--  log4j2 桥接包 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.3</version>
        </dependency>

        <!--  log4j2 实现 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.3</version>
        </dependency>
        <!--  log4j2 实现 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.3</version>
        </dependency>







        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.3.4</version>
        </dependency>

    </dependencies>


</project>

PS:Log4j 2 包含了基于LMAX 分离库的下一代的异步日志系统,在多线程环境下,异步日志系统比 Log4j 1.x 和Logback 提高了10倍性能提升(吞吐量和延迟率 )。原文如下:

Log4j 2 contains next-generation Asynchronous Loggers based on the LMAX Disruptor library. In multi-threaded scenarios Asynchronous Loggers have 10 times higher throughput and orders of magnitude lower latency than Log4j 1.x and Logback.

0人推荐
随时随地看视频
慕课网APP