微服务架构师封神之路03-使用log4j2统一微服务内部不同日志工具

日志是软件架构设计中首先要考虑的问题

在设计一个微服务应用的过程中,我首先想到的是日志架构的设计。
人世间的所有应用系统,无论什么业务,无论它是否以数据为中心,它必然会有日志系统。有了日志,我们才知道应用中发生了什么。日志无外乎有两个用途:第一,监控当前应用系统的运行状态;第二,回溯系统中发生的错误,帮助开发人员分析问题。所以日志对任何系统来说都是首要的、不可或缺的。虽然它看起来是那么不起眼。

为什么我要考虑统一日志工具的问题

首先我先设定一个前题:『同一个应用系统的日志必须写在同一个日志文件中』
如果没有这个前题也就没有讨论下去的必要了。系统里并存800个日志工具也完全没有问题,大不了同时输出800个日志文件呗?!哥们,那你要这么说就没意思了!…

我是这样想的。当我们构建微服务的时候,无非有两种可能:第一种,完完全全的一个新的应用,从头到脚都要我们一行一行的代码码出来;另一种,就是老的系统还在,但我们要进行重构,比如原来是monolithic architecture,现在我们要重新设计另一个微服务架构的版本。

  • 第一种情况,我们的服务还要依赖一些第三方的模块,大概率它们不会和我们采用一样的日志工具。这些模块的日志要不要出现在微服务的日志中?
  • 第二种情况,我们为了多快好省的建设新的微服务应用,避免不了要大面积的从旧的系统中拷贝代码。旧代码的日志肯定不是用log4j2写的啊!如果为了减少修改日志代码所引入的风险,可不可以不修改这些日志代码,但是仍然可以让应用享受到最新的日志工具(log4j2)所带来的性能优势?

统一系统的日志工具就是为了解决以上两个问题。这两个问题的答案也都是肯定的。日志工具的设计者们不可能不考虑到这两个问题。

我的微服务应用采用springboot框架,日志工具选型我选了log4j2。如果你想知道这个故事的来龙去脉,请参看『微服务架构师封神之路01』和『微服务架构师封神之路02』。闲话少说,我把我为微服务统一日志工具的任务分解成一下两个步骤。

Enable log4j2 in springboot

springboot的原生日志系统是logback,它不需要做额外的配置,自动生效,默认将日志写入console。
现在我们要让log4j2生效需要做一下三件事:

  • Disable logback in pom.xml。Exclude spring-boot-starter-logging from spring-boot-starter-web [1]
  • Enable log4j2 in pom.xml。添加依赖spring-boot-starter-log4j2 [2]
  • 添加log4j2.xml。将lgo4j2的配置文件加入classpath中,我们可以把它放在src/main/resources下面

pom.xml

Please pay attention on [1] and [2]

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!-- [1] -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- [2] -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
    </dependencies>

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="com.b5wang.cloudlab.helloworld" level="debug" />
        <Root level="error">
            <AppenderRef ref="STDOUT"/>
        </Root>
    </Loggers>
</Configuration>

都有哪些日志工具被统一了

列出常见的Java日志工具:

  • JUL (java.util.logging)
  • JCL (Apache commons logging)
  • Log4j
  • SLF4j / Logback
  • Log4j2

目前,除了log4j还不支持。其它以上所有的日志都可以通过上面的log4j2的配置统一输出。道理很简单,spring-boot-starter-log4j2提供了这些日志工具与log4j2完整的对接工具。无论是在我自己的微服务代码中,还是第三方依赖的代码中,出现以下任意的Logger的调用,最终都会输出到log4j2的日志中。


    /** log4j2
     * fatal, error, warn, info, debug, trace
     * */
    private static final org.apache.logging.log4j.Logger LOG4J2_LOGGER = org.apache.logging.log4j.LogManager.getLogger(AppMain.class);

    /** slf4j
     * error, warn, info, debug, trace
     * If want fatal, you need create by yourself with marker and specific apender
     *
     * logback is the same api as slf4j. Logback is implementation
     * */
    private static final org.slf4j.Logger SLF4J_LOGGER = org.slf4j.LoggerFactory.getLogger(AppMain.class);

    /** JUL
     * SEVERE (highest level)
     * WARNING
     * INFO
     * CONFIG
     * FINE
     * FINER
     * FINEST (lowest level)
     * */
    private static final java.util.logging.Logger JUL_LOGGER = java.util.logging.Logger.getLogger(AppMain.class.getName());

    /** JCL
     * fatal, error, warn, info, debug, trace
     * */
    private static final org.apache.commons.logging.Log JCL_LOG = org.apache.commons.logging.LogFactory.getLog(AppMain.class);

如何将log4j也统一进来?

只要在pom.xml中增加一个依赖。

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-1.2-api</artifactId>
            <version>${log4j-1.2-api.version}</version>
        </dependency>

现在微服务代码中,和第三方依赖中对log4j日志接口的调用都会输出到log4j2指定的地方了。

    /** log4j
     *
     * */
    private static final org.apache.log4j.Logger LOG4J_LOGGER = org.apache.log4j.Logger.getLogger(AppMain.class);

例外

目前我们只是尝试了简单的调用日志接口而已,这种情况下的统一是完全可行,而且十分简单方便。
当如果代码中还涉及到对日志工具更深层次的调用,比如编程式的配置,或者调用了非日志接口的程序,这种统一日志的思想就很难通过像上面演示的简单的配置来实现的。
如果你在现实工作中遇到过类似的问题或者用例,欢迎留言交流!

今天就想到这里! 拜拜! : )

参考与延伸阅读

How to migrate log4j to log4j2: https://logging.apache.org/log4j/log4j-2.2/manual/migration.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值