Skip to content

Latest commit

 

History

History
268 lines (192 loc) · 15.6 KB

File metadata and controls

268 lines (192 loc) · 15.6 KB

8.1 概述

FIT 框架提供了一套日志记录接口,并提供了 "控制台输出"、"Log4j2" 这两种日志实现和配置功能。如果你的应用使用了 fit-starter 或者使用了默认的 FIT 框架二进制包,此时日志使用控制台输出的方式记录:当你初始化记录器(Logger类)后,通过记录器记录的日志,都会被预设为控制台输出。你也可以通过切换成 Log4j2 实现,将日志信息输出到文件。 此外,你也可以自己实现日志记录接口,提供自定义实现日志满足需求,以此来接入其他的第三方日志依赖库进行实现,如 Java Util Logging、Logback 等。

8.2 基本使用

FIT 框架提供的日志记录接口主要包含 Logger 记录器接口和 LoggerFactotry 记录器的工厂接口。由于这两个接口包含在 fit-api 中,所以如果需要在业务代码能够正常编写打印日志的代码逻辑和编译通过,需要引入 fit-api 依赖或者引入 fit-starter。需要注意的是,这仅仅只是能通过编译,如果想要应用服务在实际运行中能够正确输出日志,还需要引入日志记录接口的实现,你可以参考 8.3 节和 8.4 节引入自己所需的实现,也可以自定义实现。

在业务中打印日志很简单,只需要实例化记录器对象,并调用日志打印方法即可。 记录器对象可以通过 Logger 接口的 get 方法,也可以通过 LoggerFactotry 来获取,记录器对象还提供了一系列日志打印方法和日志级别判断方法。以下代码为展示打印一条 info 级别信息的基本步骤:

import modelengine.fitframework.log.Logger;

Logger logger = Logger.get(Main.class);
logger.info("Prepare to start FIT application");

我们建议记录器对象作为日志打印所在类的常量值,get 参数为该类的 class 对象。同时需要注意的是,如果日志配置的级别高于日志打印的级别,此时应用运行时,控制台并不会有日志输出。如何配置日志打印级别可以参照 8.2.1 节。

8.2.1 日志级别

日志级别可以通过配置项 logging.level 来设置,配置项的值可以是 ERROR 、WARN、INFO、DEBUG 或 TRACE 的某一项,日志优先级从高到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE。可以在配置文件 application.yml 中,按下图所示进行配置项的配置:

logging:
  level: 'INFO'

此时,INFO 级别以及该级别优先级更高的日志级别信息会被打印。你也可以通过在自己的业务代码中设置,如下所示:

Loggers.getFactory().setGlobalLevel(Logger.Level.INFO);

通过这种方式设置,会将全局的日志级别调整为 INFO。你也可以指定包路径及其子包路径,将该范围的日志记录级别调整为指定值,如下所示

Loggers.getFactory().setLevels("modelengine.fitframework.log", Logger.Level.INFO);

如果你只是仅仅想对某个记录器设置日志级别,可以如下编写代码:

Logger log = Logger.get(DefaultConfigurationClient.class);
log.setLevel(Logger.Level.INFO);

8.3 控制台输出

8.3.1 基于 IDEA 启动的场景

如果你的应用模块使用了 fit-starter,此时日志默认会使用控制台输出的方式记录,不需要其他的依赖配置,即可进行日志系统的初始化和使用。否则,你需要添加以下依赖,才能使日志打印生效:

<dependency>
    <groupId>org.fitframework</groupId>
    <artifactId>fit-log-console</artifactId>
    <version>${fit.version}</version>
</dependency>

此外,在插件模块只需要有 fit-api 依赖即可,原因是日志记录接口都是在 fit-api,插件本身并不需要日志记录的实现依赖。

8.3.2 基于 JAR 包启动的场景

在基于 JAR 包启动的场景下使用控制台输出打印日志,配置方式和使用方式与 "8.3.1 基于 IDEA 启动的场景" 一致,可参考上文所示。

8.3.3 基于 FIT 二进制引擎包启动的场景

由于 FIT 框架引擎包默认带有 fit-log-console 依赖包,只需要用户在插件编写业务代码时,使用 fit-api 依赖即可。

8.3.4 日志格式

通过 fit-log-console 打印,日志输出格式类似于下面的例子:

[2023-12-06 10:52:18.533] [INFO ] [main] [modelengine.fit.http.server.handler.ReflectMappingHandlerRegistry] Register http handler group successfully. [group=modelengine.fit.demo.controller.FileController]
[2023-12-06 10:52:18.533] [INFO ] [main] [modelengine.fit.http.server.handler.ReflectMappingHandlerRegistry] Register http handler group successfully. [group=modelengine.fit.demo.controller.UserController]
[2023-12-06 10:52:18.534] [INFO ] [main] [modelengine.fit.http.server.handler.ReflectMappingHandlerRegistry] Register http handler group successfully. [group=modelengine.fit.demo.controller.UserDecController]
[2023-12-06 10:52:18.534] [INFO ] [main] [modelengine.fit.http.server.handler.ReflectMappingHandlerRegistry] Register http handler group successfully. [group=modelengine.fit.http.server.handler.OptionsHttpHandler]
[2023-12-06 10:52:18.535] [INFO ] [main] [modelengine.fit.http.server.handler.ReflectMappingHandlerRegistry] Register http handler group successfully. [group=modelengine.fit.http.server.handler.StaticResourceHttpHandler]
[2023-12-06 10:52:18.535] [INFO ] [main] [modelengine.fit.http.server.handler.ReflectMappingHandlerRegistry] Register http handler group successfully. [group=modelengine.fit.http.openapi3.swagger.DocumentController]
[2023-12-06 10:52:18.537] [INFO ] [main] [modelengine.fitframework.runtime.direct.DirectFitRuntime] FIT application started. [version=3.2.5-SNAPSHOT]
[2023-12-06 10:52:18.604] [INFO ] [netty-http-server-thread-0] [modelengine.fit.http.server.netty.NettyHttpClassicServer] Start netty http server successfully. [httpPort=8090]

输出的项目如下:

  • 日期和时间:格式为 "年-月-日 小时:分:秒.毫秒"。
  • 日志级别:级别内容包含在方框号中,其值为 ERROR、WARN、INFO、DEBUG 或 TRACE 中的某一项。
  • 线程名称:线程名称包含在方框号中,其值为日志打印时所执行的线程名称。
  • 类名:类名包含在方框号中,其值为日志打印时所属的类名全限名称。
  • 日志信息。

8.4 基于 FIT 的 Log4j2 的扩展实现

8.4.1 基于 IDEA 启动的场景

FIT 框架提供了 Log4j2 的扩展实现,通过应用模块添加以下依赖即可:

<dependency>
    <groupId>org.fitframework</groupId>
    <artifactId>fit-log-log4j2</artifactId>
    <version>${fit.version}</version>
</dependency>

需要注意的是,如果原来的 pom 文件包含 fit-log-console 依赖,需要移除,即去除 "控制台输出" 的日志输出方式。同时考虑到 fit-starter 依赖本身也包含了 fit-log-console 的依赖,所以如果使用了 fit-starter,则需要通过 exclusion 标签排除 fit-log-console 依赖。如下所示:

<dependency>
    <groupId>org.fitframework</groupId>
    <artifactId>fit-starter</artifactId>
    <version>${fit.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.fitframework</groupId>
            <artifactId>fit-log-console</artifactId>
        </exclusion>
    </exclusions>
</dependency>

此外,在插件模块只需要有 fit-api 依赖即可,原因是日志记录接口都是在 fit-api,插件本身并不需要日志记录的实现依赖。

8.4.2 基于 JAR 包启动的场景

在基于 JAR 包启动的场景下使用控制台输出打印日志 ,配置方式和使用方式与 "8.3.1 基于 IDEA 启动的场景" 一致,可参考上文所示。

8.4.3 基于 FIT 二进制引擎包启动的场景

由于 FIT 框架引擎包默认带有 fit-log-console 依赖包,所以若想在该场景下使用 fit-log-log4j2,需要在 fitframework/lib 目录下中删除 fit-log-console ,同时放入 fit-log-log4j2log4j-apilog4j-core 这三个依赖 jar 包。

8.4.4 日志配置

由于 fit-log-log4j2fit-log-console 实现了同一套日志记录接口,所以你可以与控制台输出相同的方式去初始化记录器对象和使用它进行日志打印。日志的格式是由 Log4j2 的配置文件决定,配置内容可以参考 Log4j2 的官方文档,你可以通过设置 logging.config 来指定配置文件的位置。

需要注意的是,FIT 框架旨在消除对第三方依赖的需求,从而在没有外部库的情况下实现编码。但是,这样会遇到一些准确性问题,特别是在使用日志行号方面。当使用 fit-log-log4j2 的依赖插件进行日志打印时,底层实现在用户逻辑代码和 Log4j2 日志系统添加了额外的层,这会导致日志行号反映的是底层的框架代码行数,而非用户逻辑代码行数,行号的不准确性可能会影响到用户定位问题。从另外一方面考虑,日志显示行数可能会影响到性能,且会有敏感信息暴露的风险,所以在实际应用中,是否需要开启行数打印需要综合考量。如果用户不需要考虑行数显示,则可以直接使用 fit-log-log4j2 依赖;如果需要考虑行数显示,可以参考 8.5 节 使用标准 SLF4J 的方式打印。

8.5 基于原生的 Log4j2

用户使用该方式打印日志信息时,不需要考虑 FIT 框架提供的日志记录接口,而是完全使用标准的 SLF4J 的使用方式去打印日志。需要了解的是,SLF4J 是一个日志框架,它是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,它需要和具体的日志框架来配合使用。而 Log4j2是一个日志实现,它是一种记录日志的具体实现。所以需要 SLF4J 和 Log4J2 的组合使用,才能打印出准确的日志。

8.5.1 基于 IDEA 启动的场景

应用模块配置

  • 在该场景下,需要在应用模块引入 SLF4J 和 Log4j2 的接口和实现,如下图所示:
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>${log4j2.version}</version>
</dependency>

其中 ${slf4j.version} 表示 slf4j 的版本号,${log4j2.version} 表示 log4j2 的版本号。

  • 此外在该 pom 文件中,标识符 idfit-build-maven-plugin 构建插件加入以下内容:
<configuration>
    <sharedDependencies>
        <sharedDependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </sharedDependency>
        <sharedDependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
        </sharedDependency>
        <sharedDependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
        </sharedDependency>
        <sharedDependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
        </sharedDependency>
    </sharedDependencies>
</configuration>

通过修改 pom 文件以上的两处配置,应用在编译过程中,会将 SLF4J 和 Log4j2 相关的 JAR 包放置在应用的 shared 目录。这样的话,应用启动时,SharedClassLoader 会加载日志相关的类,各个插件的业务逻辑都能够正确获取到日志类的实现,并能够正常打印。如果没有 <configuration> 的配置或者配置出错,比如将以上配置在插件模块的 pom 文件中,则由于类隔离机制,会导致业务日志打印时获取不到日志类信息而使得应用报错。FIT 框架的类隔离机制,可以参考第十一章类加载机制

  • 如果原来的 pom 文件还含有 fit-starter 的依赖,则需要排除掉 fit-log-console 的依赖。如下所示:
<dependency>
    <groupId>org.fitframework</groupId>
    <artifactId>fit-starter</artifactId>
    <version>${fit.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.fitframework</groupId>
            <artifactId>fit-log-console</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  • 在该场景下,用户可以将 Log4j2 的配置文件 Log4j2.xml,放置在应用的 resources 资源目录下,应用启动时,会自动读取 resources 资源目录下的文件。你也可以通过在命令行或者环境变量加上 log4j2.configurationFile=filePath 的配置项,并通过 -D 的方式配置,来指定 Log4j2.xml 的文件位置。

插件模块配置

  • 在插件模块的 pom 文件中,添加以下依赖:
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
    <scope>provided</scope>
</dependency>

其中 ${slf4j.version} 表示 slf4j 的版本号。

插件模块只需要修改以上项即可。原因是根据双亲委派机制,SharedClassLoader 类加载器作为插件 PluginClassLoader 的父类加载器,会插件中的类委派到 SharedClassLoader 类加载器,而应用模块已经通过 SharedClassLoader 类加载器引入了日志的实现类,所以插件模块不需要单独的引入日志实现类。

使用 Log4j2

由于此时是使用标准 SLF4J 来使用日志打印,而不是 FIT 框架自身的日志接口系统。所以在使用 Log4j2 时,需要通过 slf4j-api 依赖包中的 LoggerFactory 类进行实例化:

private static final Logger log = LoggerFactory.getLogger(AssistantController.class);

之后,在需要进行日志打印的地方,可以使用实例化后的 LOG 对象进行日志输出:

log.info("Hello World.");

8.5.2 基于 JAR 包启动的场景

在基于 JAR 包启动的场景下使用原生的 Log4j2,配置方式和使用方式与 "8.5.1 基于 IDEA 启动的场景" 一致,可参考上文所示。

8.5.3 基于 FIT 二进制引擎包启动的场景

在基于 FIT 二进制引擎包启动的场景下使用 Log4j2,插件模块配置和使用方式与 "8.5.1 基于 IDEA 启动的场景" 一致,可参考上文所示。

区别之处在于:

(1)在该场景下,因为项目模块只有插件模块,不含有用户自己的应用模块。所以不需要考虑 "应用模块配置"。

(2)编译源码后,需要在 build/shared 目录下放入 log4j-api、log4j-core、log4j-slf4j-impl、slf4j-api 的 jar 包。应用启动时,SharedClassLoader 会加载 shared 目录下所有的 JAR 包并扫描里面的类。这样的话,日志相关的类将由 SharedClassLoader类加载器加载,各个插件的业务逻辑在运行过程中,通过委托机制,都能够正确获取到日志类的实现,因此可以正常打印。

(3)放置 log4j2.xml 配置文件,并在应用启动命令中加入 log4j2.configurationFile 的配置项用于指定配置文件的位置,并通过 -D 的方式配置。例如,用户可以将 log4j2.xml 配置文件放置在 build/conf 下,则启动命令为 fit start server.http.port=8080 -Dlog4j2.configurationFile=./conf/log4j2.xml