log4j2升级为logback,logback+slf4jcommons-logging+Jboss-logging(SSH项目)

Java日志 - log4j2升级为logback,涉及commons-logging、slf4j、Jboss-logging日志组件(SSH项目)

1 前言

SSH框架中已集成log4j2,因为要通过kafka接入elk,因为接入demo采用的是logback作为日志组件,所以需要将日志组件改为logback,由logback生产日志发送给kafka,接入到elk。因为SSH框架老旧,改造中又涉及到的日志工具:lagback、log4j2、commons-logging、slf4j、jboss-logging,遇到较多问题,因此梳理出了改造过程。

关于java各日志工具的解释、jar包关系可以看,或者是log4j改造为logback,可以结合两篇文章参考:log4j升级为log4j2,log4j2+slf4j+commons-logging+Jboss-logging(SSH项目)

slf4j 与 logback 集成可能的改造点

  • log4j2 日志工具相关依赖删除
  • 保留slf4j与commons-logging, commons-logging委托给slf4j
  • 保留Jboss-logging与slf4j集成,Jboss-logging是自动匹配log4j,可能要搭建Jboss -> slf4j -> logback 的桥梁
  • 增加logback相关依赖,搭建slf4j->logback,logback作为日志实现

2 改造步骤及问题解决(log4j2升级至logback)

2.1 日志实现工具的替换:log4j2移除,替换为logback

  • 删除log4j1依赖及配置文件:log4j2.xml、log4j-api-2.11.0.jar、log4j-core-2.11.0.jar
  • 增加logback的依赖:logback-classic-1.2.3.jar,logback-core-1.2.3.jar
  • 增加logback的配置文件:logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 日志输出格式定义 -->
    <property name="LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} - %X{hotel} - %X{userName} %-5level %logger{50} - %msg%n"/>
    <!-- 日志输出文件性格定义 -->
    <Property name="LOG_FILE_PATH" value="${catalina.home}/projectName_log"/>
    <Property name="ARCHIVE_LOG_FILE_PATH" value="${LOG_FILE_PATH}/archiveLog"/>

    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!--info 级别的日志-->
    <!-- 按照每天生成日志文件 -->
    <appender name="ROLLING_LOG_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <file>${LOG_FILE_PATH}/info.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <fileNamePattern>${ARCHIVE_LOG_FILE_PATH}/info-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <maxFileSize>50MB</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>180</MaxHistory>
        </rollingPolicy>
    </appender>

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="ROLLING_LOG_INFO"/>
    </root>
</configuration>

logback更详细的配置文件情况可以看这篇:logback 配置文件详解

注意,若代码中存在使用log4j2直接作为日志输出,因修改日志输出代码,采用slf4j编程,见2.2 使用slf4j API的方式

2.2 logback、slf4j、commons-logging的集成 (解决spring日志的输出问题)

  • 保留 jcl-over-slf4j-1.7.5.jar,实现JCL与slf4j的集成。
  • 保留 slf4j相关的jar包:slf4j-api-1.7.5.jar
  • 删除掉原本slf4j与log4j2的桥梁包:log4j-slf4j-impl-2.11.0.jar,不删除则会和其他桥梁冲突,slf4j不知道要将日志实现交给谁来处理。
  • 同log4j2+slf4j不同的是,logback+slf4j不需要额外的桥梁包。

和log4j2集成类似,已经集成了slf4j,建议采用slf4j提供的API进行编程,而不是采取使用logback的API。采用slf4j,后续具体实现日志的工具有进行升级更换,如换成logback,则不需要再改程序代码,只需要修改相应桥梁的jar包即可,采用slf4j编写如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SystemAction {
	private final Logger log = LoggerFactory.getLogger(SystemAction.class);
	public void valid() {
		log.info("效验通过slf4j日志输出");
	}
}

2.3 jboss-logging、logback、slf4j的集成

Hibernate自带Jboss-logging,没有指明日志实现,jboss-logging默认会从:jboss、jdk、log4j2、log4j、slf4j的顺序去找(不同版本的jboss-logging顺序可能不同)

//jboss-logging的源码
//package org.jboss.logging.LoggerProviders
try {
    String loggerProvider = SecurityActions.getSystemProperty("org.jboss.logging.provider");
    if (loggerProvider != null) {
        if ("jboss".equalsIgnoreCase(loggerProvider)) {
            return tryJBossLogManager(cl, "system property");
        }

        if ("jdk".equalsIgnoreCase(loggerProvider)) {
            return tryJDK("system property");
        }

        if ("log4j2".equalsIgnoreCase(loggerProvider)) {
            return tryLog4j2(cl, "system property");
        }

        if ("log4j".equalsIgnoreCase(loggerProvider)) {
            return tryLog4j(cl, "system property");
        }
        if ("slf4j".equalsIgnoreCase(loggerProvider)) {
            return trySlf4j("system property");
        }
    }
} catch (Throwable var8) {
    
}

按理说我们删掉了log4j2,会采用slf4j,最终通过logback实现日志输出,但实际并非如此。集成后在Jenkins构建执行单元测试时,在Sring加载上下文过程中会出现如下异常:

Caused by: java.lang.NoSuchFieldError: TRACE
	at org.jboss.logging.Log4jLogger.translate(Log4jLogger.java:55)
	at org.jboss.logging.Log4jLogger.isEnabled(Log4jLogger.java:35)
	at org.jboss.logging.Logger.isTraceEnabled(Logger.java:98)
	at org.hibernate.internal.CoreMessageLogger_$logger.isTraceEnabled(CoreMessageLogger_$logger.java:415)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:145)
	at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131)
	...

这种异常的解决有两种方式:

  • 第一种是保留log4j2,但仅作为Jboss-logging的日志实现,因为去掉了slf4j和log4j2的桥梁(log4j-slf4j-impl-2.11.0.jar),不会影响到slf4j编写的日志,通过logback实现日志输出。(不建议这种方式,留着两个日志的实现工具,多余并且并不能完美处理,会导致出现部分日志并不通过logback,日志缺失)
  • 第二种是指定Jboss-logging通过slf4j作为日志输出,最终通过logback实现(研究了好久~推荐),实现方式是通过在spring配置中配置,Sring启动时指定。
<!-- 设置修改Hibernate jboss-logging 日志输出指定为SLF4J-->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject">
            <!-- System.getProperties() -->
            <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
                <property name="targetClass" value="java.lang.System"/>
                <property name="targetMethod" value="getProperties"/>
            </bean>
        </property>
        <property name="targetMethod" value="putAll"/>
        <property name="arguments">
            <!-- The new Properties -->
            <props>
                <prop key="org.jboss.logging.provider">slf4j</prop>
            </props>
        </property>
    </bean>

上述不是唯一的方式,该文章介绍了多种指定Jboss-logging委托给slf4j的方式:Jboss-logging委托给slf4j

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值