JFinal4.8发布前,我们JBolt极速开发平台需要在日志方面做处理,使用SlF4J+Log4j2.
SLF4J,一个日志门面,类似于JDBC操作数据库,抽象出一层,底层针对不同数据库有自己的实现。日志也是一样,使用SLF4J,实现部分可以使用LogBack,也可以使用Log4j2等具体实现,当然常用的还有simple实现。
JBolt极速开发平台里,JFinal4.8没发布前,自己实现JFinal的Slf4jLogFactory,在MainConfig里配置一下就可以了。
这里不再赘述,好在波总在JFinal4.8里对日志这块做了精心打磨,已经完美。

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

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



当然开启整个需要导入相关的类库了,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实现。

启动项目,就可以看到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>先来看最后实现的效果把!




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

这些地方需要配合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 桥接器的话,控制台会有错误信息。

官方文档描述

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

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