【分享】使用JFinal4.8中的Slf4J日志门面配置,具体实现用Log4j2

JFinal4.8发布前,我们JBolt极速开发平台需要在日志方面做处理,使用SlF4J+Log4j2.

SLF4J,一个日志门面,类似于JDBC操作数据库,抽象出一层,底层针对不同数据库有自己的实现。日志也是一样,使用SLF4J,实现部分可以使用LogBack,也可以使用Log4j2等具体实现,当然常用的还有simple实现。

JBolt极速开发平台里,JFinal4.8没发布前,自己实现JFinal的Slf4jLogFactory,在MainConfig里配置一下就可以了。

这里不再赘述,好在波总在JFinal4.8里对日志这块做了精心打磨,已经完美。


image.png

这样在JFinal中开启也非常简单,一行代码启用Slf4j.

image.png

具体调用日志输出的用法:

image.png


image.pngimage.png


当然开启整个需要导入相关的类库了,SLF4J的类库和具体实现类库,都要的。

<properties>
    <slf4j.version>1.7.25</slf4j.version>
</properties>
<!--门面-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<!--桥接器:告诉slf4j使用slf4j-simple-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>${slf4j.version}</version>
</dependency>


先来使用slf4j-simple实现。

image.png


启动项目,就可以看到Simple的实现效果了,确实还挺简单的,一行一条。

但是JBolt项目对日志要求比较复杂,JBolt是一个开发平台,既要平时开发测试,调试,又要针对数据,sql,参数等做跟踪,还要进行日志归档,可以按照日期和大小自动进行归档。

所以,最后选择了Log4j2的实现,不在使用Simple。

看一下POM里引入。

<!--门面-->
		<dependency>
		    <groupId>org.slf4j</groupId>
		    <artifactId>slf4j-api</artifactId>
		    <version>${slf4j.version}</version>
		</dependency>
		<!--桥接器:告诉slf4j使用Log4j2-->
		<dependency>
		    <groupId>org.apache.logging.log4j</groupId>
		    <artifactId>log4j-slf4j-impl</artifactId>
		    <version>${log4j2.version}</version>
		    <exclusions>
		        <exclusion>
		            <artifactId>slf4j-api</artifactId>
		            <groupId>org.slf4j</groupId>
		        </exclusion>
		    </exclusions>
		</dependency>
		<!--具体实现,log4j2-->
		<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>

先来看最后实现的效果把!

image.png

image.pngimage.png

image.png


这里来说明一下,JBolt里需要把日志,按照功能划分出来类型,有专门在测试模式下开启的比如全Sql监控日志、自动缓存执行监控日志,还有就是平台里种重要手工记录的关键节点输出日志,debug,error,info,sql,等不同类型归档分类日志等,以及针对JFinal自身的ActionReport 默认使用sysout输出,JBolt中可以定制开启,将actionReport输出到具体分类下的日志文件里,便于在线出问题时候配合快速开启自检模式。

image.png


这些地方需要配合Log4j2的配置文件,进行日志的格式化输出。

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
    <appenders>
 		<Console name="DruidSqlConsole" target="SYSTEM_OUT">
            <!--只接受程序中DEBUG级别的日志进行处理-->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[==JBolt Database Sql Log==]%n%msg%n%xEx[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level]%n%n"/>
        </Console>
        <Console name="JBoltConsole" target="SYSTEM_OUT">
            <!--只接受程序中DEBUG级别的日志进行处理-->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[==JBolt System Log==]%n%msg%n%xEx[%level] [(%class{36}.java:%L) %M] [%d{yyyy-MM-dd HH:mm:ss.SSS}]%n%n"/>
        </Console>
        <Console name="Console" target="SYSTEM_OUT">
            <!--只接受程序中DEBUG级别的日志进行处理-->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[==JBolt Log==]%n%msg%n%xEx[%level] [(%class{36}.java:%L) %M] [%d{yyyy-MM-dd HH:mm:ss.SSS}]%n%n"/>
        </Console>
        
        <!-- JBolt中的action Report 控制台输出LGO -->
         <Console name="JBoltActionReportConsole" target="SYSTEM_OUT">
            <!--只接受程序中DEBUG级别的日志进行处理-->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[==JBolt Action Report Log==]%msg%xEx[%level] [(%class{36}.java:%L) %M] [%d{yyyy-MM-dd HH:mm:ss.SSS}]%n%n"/>
        </Console>
        <!--处理actionreport日志,并把该日志放到logs/jfinal_action_report.log文件中-->
        <RollingFile name="RollingFileJBoltActionReport" fileName="./logs/jfinal_action_report.log"
                     filePattern="logs/$${date:yyyy-MM}/jfinal_action_report-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="DEBUG"/>
                <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
        
        <!-- JBolt中的JBoltAutoCache自动化缓存 CacheKey Debug 控制台输出LOG -->
         <Console name="JBoltAutoCacheConsole" target="SYSTEM_OUT">
            <!--只接受程序中DEBUG级别的日志进行处理-->
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="[==JBolt Auto Cache Log==]%n%msg%n%xEx[%level] [(%class{36}.java:%L) %M] [%d{yyyy-MM-dd HH:mm:ss.SSS}]%n%n"/>
        </Console>
        
        <!--处理jboltAutoCache日志,并把该日志放到logs/jbolt_auto_cache_debug.log文件中-->
        <RollingFile name="RollingFileJBoltAutoCache" fileName="./logs/jbolt_auto_cache_debug.log"
                     filePattern="logs/$${date:yyyy-MM}/jbolt_auto_cache_debug-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="DEBUG"/>
                <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level (%class{36}.java:%L) %M - %msg%n%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--处理DEBUG级别的日志,并把该日志放到logs/debug.log文件中-->
        <!--打印出DEBUG级别日志,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileDebug" fileName="./logs/debug.log"
                     filePattern="logs/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="DEBUG"/>
                <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level (%class{36}.java:%L) %M - %msg%n%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--处理INFO级别的日志,并把该日志放到logs/info.log文件中-->
        <RollingFile name="RollingFileInfo" fileName="./logs/info.log"
                     filePattern="logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <!--只接受INFO级别的日志,其余的全部拒绝处理-->
                <ThresholdFilter level="INFO"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level (%class{36}.java:%L) %M - %msg%n%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--处理WARN级别的日志,并把该日志放到logs/warn.log文件中-->
        <RollingFile name="RollingFileWarn" fileName="./logs/warn.log"
                     filePattern="logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
            <Filters>
                <ThresholdFilter level="WARN"/>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level (%class{36}.java:%L) %M - %msg%n%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--处理error级别的日志,并把该日志放到logs/error.log文件中-->
        <RollingFile name="RollingFileError" fileName="./logs/error.log"
                     filePattern="logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <ThresholdFilter level="ERROR"/>
            <PatternLayout
                    pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level (%class{36}.java:%L) %M - %msg%n%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
 
        <!--druid的日志记录追加器-->
        <RollingFile name="druidSqlRollingFile" fileName="./logs/druid-sql.log"
                     filePattern="logs/$${date:yyyy-MM}/api-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %L %M - %msg%n%xEx%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>
    </appenders>
 
    <loggers>
        <root level="DEBUG">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
            <appender-ref ref="RollingFileDebug"/>
        </root>
 
        <!--记录druid-sql的记录-->
        <logger name="druid.sql.Statement" level="DEBUG" additivity="false">
            <appender-ref ref="DruidSqlConsole"/>
            <appender-ref ref="druidSqlRollingFile"/>
        </logger>
        <logger name="cn.jbolt" level="DEBUG" additivity="false">
            <appender-ref ref="JBoltConsole"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
            <appender-ref ref="RollingFileDebug"/>
        </logger>
        
        <!-- 配置jfinal action report -->
        <logger name="JBoltActionReportLog" level="DEBUG" additivity="false">
            <appender-ref ref="JBoltActionReportConsole"/>
            <appender-ref ref="RollingFileJBoltActionReport"/>
        </logger>
          <!-- 配置JboltAutoCache debug -->
        <logger name="JBoltAutoCacheLog" level="DEBUG" additivity="false">
            <appender-ref ref="JBoltAutoCacheConsole"/>
            <appender-ref ref="RollingFileJBoltAutoCache"/>
        </logger>
       
 
        <!--log4j2 自带过滤日志-->
        <Logger name="net.sf.ehcache" level="error" />
        <Logger name="cn.hutool" level="error" />
        <Logger name="org.xnio" level="error" />
        <Logger name="io.undertow" level="error" />
        <Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
        <Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
        <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
        <logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
        <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
        <Logger name="org.crsh.plugin" level="warn" />
        <logger name="org.crsh.ssh" level="warn"/>
        <Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
    </loggers>
</configuration>


在这里,总结一下,JBolt里的强大需求实现背后,离不开波总对JFinal的升级处理,再次感谢,节省大量时间和精力。


补充:

这里去掉Slf4J log4j 桥接器的话,控制台会有错误信息。

image.png

官方文档描述

image.png


如有系统日志问题需要咨询,请关注学院公众号或者加我微信咨询。


加我微信


评论区

JFinal

2019-12-27 12:02

slf4j 是个日志门面框架,jfinal 4.8 提供这个实现以后,大家可以用上各种各样自己喜欢的日志,不必纠结必须使用哪一种日志了

我记得 log4j2 应该是有 slf4j 的实现的,不需要 log4j-slf4j-impl 这个桥接器,去 log4j2 的官方文档找找与 slf4j 整合的文档看看

山东小木

2019-12-27 12:23

@JFinal


这里去掉Slf4J log4j 桥接器的话,控制台会有错误信息。



image.png



官方文档描述



image.png

l745230

2019-12-27 13:45

弱弱问一句,堆栈异常也有记录到文件中么.

JFinal

2019-12-27 17:45

@山东小木 估计是我记错了,难道是 logback 不需要桥接?

小胖

2019-12-28 09:30

是的,logback 不需要桥接

蔚蓝天空

2020-01-14 11:14

我在项目只引用了桥接包, 其他主要依赖包都是自动加载的:slf4j-api log4j-core log4j-api ,不知道有什么不良后果吗?