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 整合的文档看看